2 * \file mlt_transition.c
3 * \brief abstraction for all transition services
4 * \see mlt_transition_s
6 * Copyright (C) 2003-2009 Ushodaya Enterprises Limited
7 * \author Charles Yates <charles.yates@pandora.be>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "mlt_transition.h"
25 #include "mlt_frame.h"
32 /* Forward references */
34 static int transition_get_frame( mlt_service
this, mlt_frame_ptr frame
, int index
);
36 /** Initialize a new transition.
38 * \public \memberof mlt_transition_s
39 * \param this a transition
40 * \param child the object of a subclass
41 * \return true on error
44 int mlt_transition_init( mlt_transition
this, void *child
)
46 mlt_service service
= &this->parent
;
47 memset( this, 0, sizeof( struct mlt_transition_s
) );
49 if ( mlt_service_init( service
, this ) == 0 )
51 mlt_properties properties
= MLT_TRANSITION_PROPERTIES( this );
53 service
->get_frame
= transition_get_frame
;
54 service
->close
= ( mlt_destructor
)mlt_transition_close
;
55 service
->close_object
= this;
57 mlt_properties_set_position( properties
, "in", 0 );
58 mlt_properties_set_position( properties
, "out", 0 );
59 mlt_properties_set_int( properties
, "a_track", 0 );
60 mlt_properties_set_int( properties
, "b_track", 1 );
67 /** Create and initialize a new transition.
69 * \public \memberof mlt_transition_s
70 * \return a new transition
73 mlt_transition
mlt_transition_new( )
75 mlt_transition
this = calloc( 1, sizeof( struct mlt_transition_s
) );
77 mlt_transition_init( this, NULL
);
81 /** Get the service class interface.
83 * \public \memberof mlt_transition_s
84 * \param this a transition
85 * \return the service class
86 * \see MLT_TRANSITION_SERVICE
89 mlt_service
mlt_transition_service( mlt_transition
this )
91 return this != NULL ?
&this->parent
: NULL
;
94 /** Get the properties interface.
96 * \public \memberof mlt_transition_s
97 * \param this a transition
98 * \return the transition's properties
99 * \see MLT_TRANSITION_PROPERTIES
102 mlt_properties
mlt_transition_properties( mlt_transition
this )
104 return MLT_TRANSITION_PROPERTIES( this );
107 /** Connect this transition with a producers a and b tracks.
109 * \public \memberof mlt_transition_s
110 * \param this a transition
111 * \param producer a producer
112 * \param a_track the track index of the first input
113 * \param b_track the track index of the second index
114 * \return true on error
117 int mlt_transition_connect( mlt_transition
this, mlt_service producer
, int a_track
, int b_track
)
119 int ret
= mlt_service_connect_producer( &this->parent
, producer
, a_track
);
122 mlt_properties properties
= MLT_TRANSITION_PROPERTIES( this );
123 this->producer
= producer
;
124 mlt_properties_set_int( properties
, "a_track", a_track
);
125 mlt_properties_set_int( properties
, "b_track", b_track
);
130 /** Set the starting and ending time for when the transition is active.
132 * \public \memberof mlt_transition_s
133 * \param this a transition
134 * \param in the starting time
135 * \param out the ending time
138 void mlt_transition_set_in_and_out( mlt_transition
this, mlt_position in
, mlt_position out
)
140 mlt_properties properties
= MLT_TRANSITION_PROPERTIES( this );
141 mlt_properties_set_position( properties
, "in", in
);
142 mlt_properties_set_position( properties
, "out", out
);
145 /** Get the index of the a track.
147 * \public \memberof mlt_transition_s
148 * \param this a transition
149 * \return the 0-based index of the track of the first producer
152 int mlt_transition_get_a_track( mlt_transition
this )
154 return mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( this ), "a_track" );
157 /** Get the index of the b track.
159 * \public \memberof mlt_transition_s
160 * \param this a transition
161 * \return the 0-based index of the track of the second producer
164 int mlt_transition_get_b_track( mlt_transition
this )
166 return mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( this ), "b_track" );
169 /** Get the in point.
171 * \public \memberof mlt_transition_s
172 * \param this a transition
173 * \return the starting time
176 mlt_position
mlt_transition_get_in( mlt_transition
this )
178 return mlt_properties_get_position( MLT_TRANSITION_PROPERTIES( this ), "in" );
181 /** Get the out point.
183 * \public \memberof mlt_transition_s
184 * \param this a transition
185 * \return the ending time
188 mlt_position
mlt_transition_get_out( mlt_transition
this )
190 return mlt_properties_get_position( MLT_TRANSITION_PROPERTIES( this ), "out" );
193 /** Process the frame.
195 * If we have no process method (unlikely), we simply return the a_frame unmolested.
197 * \public \memberof mlt_transition_s
198 * \param this a transition
199 * \param a_frame a frame from the first producer
200 * \param b_frame a frame from the second producer
204 mlt_frame
mlt_transition_process( mlt_transition
this, mlt_frame a_frame
, mlt_frame b_frame
)
206 if ( this->process
== NULL
)
209 return this->process( this, a_frame
, b_frame
);
212 /** Get a frame from this transition.
214 The logic is complex here. A transition is typically applied to frames on the a and
215 b tracks specified in the connect method above and only if both contain valid info
216 for the transition type (this is either audio or image).
218 However, the fixed a_track may not always contain data of the correct type, eg:
220 +---------+ +-------+
221 |c1 | |c5 | <-- A(0,1) <-- B(0,2) <-- get frame
222 +---------+ +---------+-+-----+ | |
224 +----------+-----------+-+---------+ |
225 |c2 |c3 | <-----------------+
226 +----------+-------------+
228 During the overlap of c1 and c2, there is nothing for the A transition to do, so this
229 results in a no operation, but B is triggered. During the overlap of c2 and c3, again,
230 the A transition is inactive and because the B transition is pointing at track 0,
231 it too would be inactive. This isn't an ideal situation - it's better if the B
232 transition simply treats the frames from c3 as though they're the a track.
234 For this to work, we cache all frames coming from all tracks between the a and b
235 tracks. Before we process, we determine that the b frame contains someting of the
236 right type and then we determine which frame to use as the a frame (selecting a
237 matching frame from a_track to b_track - 1). If both frames contain data of the
238 correct type, we process the transition.
240 This method is invoked for each track and we return the cached frames as needed.
241 We clear the cache only when the requested frame is flagged as a 'last_track' frame.
243 * \private \memberof mlt_transition_s
244 * \param service a service
245 * \param[out] frame a frame by reference
246 * \param index 0-based track index
247 * \return true on error
250 static int transition_get_frame( mlt_service service
, mlt_frame_ptr frame
, int index
)
253 mlt_transition
this = service
->child
;
255 mlt_properties properties
= MLT_TRANSITION_PROPERTIES( this );
257 int accepts_blanks
= mlt_properties_get_int( properties
, "accepts_blanks" );
258 int a_track
= mlt_properties_get_int( properties
, "a_track" );
259 int b_track
= mlt_properties_get_int( properties
, "b_track" );
260 mlt_position in
= mlt_properties_get_position( properties
, "in" );
261 mlt_position out
= mlt_properties_get_position( properties
, "out" );
262 int always_active
= mlt_properties_get_int( properties
, "always_active" );
263 int type
= mlt_properties_get_int( properties
, "_transition_type" );
264 int reverse_order
= 0;
266 // Ensure that we have the correct order
267 if ( a_track
> b_track
)
271 b_track
= mlt_properties_get_int( properties
, "a_track" );
274 // Only act on this operation once per multitrack iteration from the tractor
279 int a_frame
= a_track
;
280 int b_frame
= b_track
;
281 mlt_position position
;
282 int ( *invalid
)( mlt_frame
) = type
== 1 ? mlt_frame_is_test_card
: mlt_frame_is_test_audio
;
284 // Initialise temporary store
285 if ( this->frames
== NULL
)
286 this->frames
= calloc( sizeof( mlt_frame
), b_track
+ 1 );
288 // Get all frames between a and b
289 for( i
= a_track
; i
<= b_track
; i
++ )
290 mlt_service_get_frame( this->producer
, &this->frames
[ i
], i
);
292 // We're holding these frames until the last_track frame property is received
295 // When we need to locate the a_frame
300 // Some transitions (esp. audio) may accept blank frames
301 active
= accepts_blanks
;
303 // If we're not active then...
306 // Hunt for the a_frame
307 while( a_frame
<= b_frame
&& invalid( this->frames
[ a_frame
] ) )
310 // Determine if we're active now
311 active
= a_frame
!= b_frame
&& !invalid( this->frames
[ b_frame
] );
316 mlt_log( service
, MLT_LOG_ERROR
, "invalid transition type\n" );
320 // Now handle the non-always active case
321 if ( active
&& !always_active
)
323 // For non-always-active transitions, we need the current position of the a frame
324 position
= mlt_frame_get_position( this->frames
[ a_frame
] );
326 // If a is in range, we're active
327 active
= position
>= in
&& position
<= out
;
330 // Finally, process the a and b frames
333 mlt_frame a_frame_ptr
= this->frames
[ !reverse_order ? a_frame
: b_frame
];
334 mlt_frame b_frame_ptr
= this->frames
[ !reverse_order ? b_frame
: a_frame
];
335 int a_hide
= mlt_properties_get_int( MLT_FRAME_PROPERTIES( a_frame_ptr
), "hide" );
336 int b_hide
= mlt_properties_get_int( MLT_FRAME_PROPERTIES( b_frame_ptr
), "hide" );
337 if ( !( a_hide
& type
) && !( b_hide
& type
) )
339 // Process the transition
340 *frame
= mlt_transition_process( this, a_frame_ptr
, b_frame_ptr
);
342 // We need to ensure that the tractor doesn't consider this frame for output
343 if ( *frame
== a_frame_ptr
)
348 mlt_properties_set_int( MLT_FRAME_PROPERTIES( a_frame_ptr
), "hide", a_hide
);
349 mlt_properties_set_int( MLT_FRAME_PROPERTIES( b_frame_ptr
), "hide", b_hide
);
354 // Obtain the frame from the cache or the producer we're attached to
355 if ( index
>= a_track
&& index
<= b_track
)
356 *frame
= this->frames
[ index
];
358 error
= mlt_service_get_frame( this->producer
, frame
, index
);
360 // Determine if that was the last track
361 this->held
= !mlt_properties_get_int( MLT_FRAME_PROPERTIES( *frame
), "last_track" );
366 /** Close and destroy the transition.
368 * \public \memberof mlt_transition_s
369 * \param this a transition
372 void mlt_transition_close( mlt_transition
this )
374 if ( this != NULL
&& mlt_properties_dec_ref( MLT_TRANSITION_PROPERTIES( this ) ) <= 0 )
376 this->parent
.close
= NULL
;
377 if ( this->close
!= NULL
)
383 mlt_service_close( &this->parent
);
384 free( this->frames
);