2 * mlt_transition.c -- abstraction for all transition services
3 * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
4 * Author: Charles Yates <charles.yates@pandora.be>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * 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
;
49 mlt_properties_set_timecode( properties
, "in", 0 );
50 mlt_properties_set_timecode( properties
, "out", 0 );
51 mlt_properties_set_int( properties
, "a_track", 0 );
52 mlt_properties_set_int( properties
, "b_track", 1 );
59 /** Get the service associated to the transition.
62 mlt_service
mlt_transition_service( mlt_transition
this )
67 /** Get the properties interface.
70 mlt_properties
mlt_transition_properties( mlt_transition
this )
72 return mlt_service_properties( mlt_transition_service( this ) );
75 /** Connect this transition with a producers a and b tracks.
78 int mlt_transition_connect( mlt_transition
this, mlt_service producer
, int a_track
, int b_track
)
80 int ret
= mlt_service_connect_producer( &this->parent
, producer
, a_track
);
83 mlt_properties properties
= mlt_transition_properties( this );
84 this->producer
= producer
;
85 mlt_properties_set_int( properties
, "a_track", a_track
);
86 mlt_properties_set_int( properties
, "b_track", b_track
);
91 /** Set the in and out points.
94 void mlt_transition_set_in_and_out( mlt_transition
this, mlt_timecode in
, mlt_timecode out
)
96 mlt_properties properties
= mlt_transition_properties( this );
97 mlt_properties_set_timecode( properties
, "in", in
);
98 mlt_properties_set_timecode( properties
, "out", out
);
101 /** Get the index of the a track.
104 int mlt_transition_get_a_track( mlt_transition
this )
106 mlt_properties properties
= mlt_transition_properties( this );
107 return mlt_properties_get_int( properties
, "a_track" );
110 /** Get the index of the b track.
113 int mlt_transition_get_b_track( mlt_transition
this )
115 mlt_properties properties
= mlt_transition_properties( this );
116 return mlt_properties_get_int( properties
, "b_track" );
119 /** Get the in point.
122 mlt_timecode
mlt_transition_get_in( mlt_transition
this )
124 mlt_properties properties
= mlt_transition_properties( this );
125 return mlt_properties_get_timecode( properties
, "in" );
128 /** Get the out point.
131 mlt_timecode
mlt_transition_get_out( mlt_transition
this )
133 mlt_properties properties
= mlt_transition_properties( this );
134 return mlt_properties_get_timecode( properties
, "out" );
137 /** Process the frame.
140 static mlt_frame
transition_process( mlt_transition
this, mlt_frame a_frame
, mlt_frame b_frame
)
142 if ( this->process
== NULL
)
144 if ( !mlt_frame_is_test_card( a_frame
) )
146 mlt_frame_close( b_frame
);
151 mlt_frame_close( a_frame
);
157 return this->process( this, a_frame
, b_frame
);
161 /** Get a frame from this filter.
163 The logic is complex here. A transition is applied to frames on the a and b tracks
164 specified in the connect method above. Since all frames are obtained via this
165 method for all tracks, we have to take special care that we only obtain the a and
166 b frames once - we do this on the first call to get a frame from either a or b.
168 After that, we have 3 cases to resolve:
170 1) if the track is the a_track and we're in the time zone, then we need to call the
171 process method to do the effect on the frame (we assign NULL to the a_frame and
172 b_frames here) otherwise, we pass on the a_frame unmolested;
173 2) if the track is the b_track and we're the in the time zone OR the b_frame is NULL,
174 then we generate a test card frame, otherwise we pass on the b frame unmolested;
175 3) For all other tracks, we get the frames on demand.
178 static int transition_get_frame( mlt_service service
, mlt_frame_ptr frame
, int index
)
180 mlt_transition
this = service
->child
;
182 mlt_properties properties
= mlt_transition_properties( this );
184 int a_track
= mlt_properties_get_int( properties
, "a_track" );
185 int b_track
= mlt_properties_get_int( properties
, "b_track" );
186 mlt_timecode in
= mlt_properties_get_timecode( properties
, "in" );
187 mlt_timecode out
= mlt_properties_get_timecode( properties
, "out" );
189 // Fetch a and b frames together...
190 if ( ( index
== a_track
|| index
== b_track
) &&
191 ( this->a_frame
== NULL
&& this->b_frame
== NULL
) )
193 mlt_service_get_frame( this->producer
, &this->a_frame
, a_track
);
194 mlt_service_get_frame( this->producer
, &this->b_frame
, b_track
);
197 // Special case track processing
198 if ( index
== a_track
)
200 // Determine if we're in the right time zone
201 mlt_timecode timecode
= mlt_frame_get_timecode( this->a_frame
);
202 if ( timecode
>= in
&& timecode
< out
)
204 // Process the transition
205 *frame
= transition_process( this, this->a_frame
, this->b_frame
);
207 // Important - NULL both frames now so that we know they're done...
208 this->a_frame
= NULL
;
209 this->b_frame
= NULL
;
213 // Pass on the 'a frame' and remember that we've done it
214 *frame
= this->a_frame
;
215 this->a_frame
= NULL
;
219 if ( index
== b_track
)
221 if ( this->b_frame
== NULL
)
223 // We're *probably* in the zone and the a frame has been requested
224 *frame
= mlt_frame_init( );
228 mlt_timecode timecode
= mlt_frame_get_timecode( this->b_frame
);
229 if ( timecode
>= in
&& timecode
< out
)
231 // We're in the zone, but the 'a frame' has not been requested yet
232 *frame
= mlt_frame_init( );
236 // We're out of the zone, pass on b and remember that we've done it
237 *frame
= this->b_frame
;
238 this->b_frame
= NULL
;
246 return mlt_service_get_frame( this->producer
, frame
, index
);
250 /** Close the transition.
253 void mlt_transition_close( mlt_transition
this )
255 if ( this->close
!= NULL
)
258 mlt_service_close( &this->parent
);