]> git.sesse.net Git - mlt/blob - src/framework/mlt_transition.c
7606ab18dab08d3f0f2d7bd086c7008d3d873b0b
[mlt] / src / framework / mlt_transition.c
1 /*
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>
5  *
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.
10  *
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.
15  *
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.
19  */
20
21 #include "config.h"
22
23 #include "mlt_transition.h"
24 #include "mlt_frame.h"
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 /** Forward references.
31 */
32
33 static int transition_get_frame( mlt_service this, mlt_frame_ptr frame, int index );
34
35 /** Constructor.
36 */
37
38 int mlt_transition_init( mlt_transition this, void *child )
39 {
40         mlt_service service = &this->parent;
41         memset( this, 0, sizeof( struct mlt_transition_s ) );
42         this->child = child;
43         if ( mlt_service_init( service, this ) == 0 )
44         {
45                 mlt_properties properties = mlt_transition_properties( this );
46
47                 service->get_frame = transition_get_frame;
48                 service->close = ( mlt_destructor )mlt_transition_close;
49                 service->close_object = this;
50
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 );
55
56                 return 0;
57         }
58         return 1;
59 }
60
61 /** Create a new transition.
62 */
63
64 mlt_transition mlt_transition_new( )
65 {
66         mlt_transition this = calloc( 1, sizeof( struct mlt_transition_s ) );
67         if ( this != NULL )
68                 mlt_transition_init( this, NULL );
69         return this;
70 }
71
72 /** Get the service associated to the transition.
73 */
74
75 mlt_service mlt_transition_service( mlt_transition this )
76 {
77         return this != NULL ? &this->parent : NULL;
78 }
79
80 /** Get the properties interface.
81 */
82
83 mlt_properties mlt_transition_properties( mlt_transition this )
84 {
85         return mlt_service_properties( mlt_transition_service( this ) );
86 }
87
88 /** Connect this transition with a producers a and b tracks.
89 */
90
91 int mlt_transition_connect( mlt_transition this, mlt_service producer, int a_track, int b_track )
92 {
93         int ret = mlt_service_connect_producer( &this->parent, producer, a_track );
94         if ( ret == 0 )
95         {
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 );
100         }
101         return ret;
102 }
103
104 /** Set the in and out points.
105 */
106
107 void mlt_transition_set_in_and_out( mlt_transition this, mlt_position in, mlt_position out )
108 {
109         mlt_properties properties = mlt_transition_properties( this );
110         mlt_properties_set_position( properties, "in", in );
111         mlt_properties_set_position( properties, "out", out );
112 }
113
114 /** Get the index of the a track.
115 */
116
117 int mlt_transition_get_a_track( mlt_transition this )
118 {
119         return mlt_properties_get_int( mlt_transition_properties( this ), "a_track" );
120 }
121
122 /** Get the index of the b track.
123 */
124
125 int mlt_transition_get_b_track( mlt_transition this )
126 {
127         return mlt_properties_get_int( mlt_transition_properties( this ), "b_track" );
128 }
129
130 /** Get the in point.
131 */
132
133 mlt_position mlt_transition_get_in( mlt_transition this )
134 {
135         return mlt_properties_get_position( mlt_transition_properties( this ), "in" );
136 }
137
138 /** Get the out point.
139 */
140
141 mlt_position mlt_transition_get_out( mlt_transition this )
142 {
143         return mlt_properties_get_position( mlt_transition_properties( this ), "out" );
144 }
145
146 /** Process the frame.
147
148         If we have no process method (unlikely), we simply return the a_frame unmolested.
149 */
150
151 mlt_frame mlt_transition_process( mlt_transition this, mlt_frame a_frame, mlt_frame b_frame )
152 {
153         if ( this->process == NULL )
154                 return a_frame;
155         else
156                 return this->process( this, a_frame, b_frame );
157 }
158
159 /** Get a frame from this filter.
160
161         The logic is complex here. A transition is applied to frames on the a and b tracks
162         specified in the connect method above. Since all frames are obtained via this 
163         method for all tracks, we have to take special care that we only obtain the a and
164         b frames once - we do this on the first call to get a frame from either a or b.
165         
166         After that, we have 2 cases to resolve:
167         
168         1)      if the track is the a_track and we're in the time zone, then we need to call the
169                 process method to do the effect on the frame and remember we've passed it on
170                 otherwise, we pass on the a_frame unmolested;
171         2)      For all other tracks, we get the frames on demand.
172 */
173
174 static int transition_get_frame( mlt_service service, mlt_frame_ptr frame, int index )
175 {
176         mlt_transition this = service->child;
177
178         mlt_properties properties = mlt_transition_properties( this );
179
180         int accepts_blanks = mlt_properties_get_int( properties, "_accepts_blanks" );
181         int a_track = mlt_properties_get_int( properties, "a_track" );
182         int b_track = mlt_properties_get_int( properties, "b_track" );
183         mlt_position in = mlt_properties_get_position( properties, "in" );
184         mlt_position out = mlt_properties_get_position( properties, "out" );
185         int always_active = mlt_properties_get_int( properties, "always_active" );
186
187         if ( ( index == a_track || index == b_track ) && !( this->a_held || this->b_held ) )
188         {
189                 mlt_service_get_frame( this->producer, &this->a_frame, a_track );
190                 mlt_service_get_frame( this->producer, &this->b_frame, b_track );
191                 this->a_held = 1;
192                 this->b_held = 1;
193         }
194         
195         // Special case track processing
196         if ( index == a_track )
197         {
198                 // Determine if we're in the right time zone
199                 mlt_position position = mlt_frame_get_position( this->a_frame );
200                 if ( always_active || ( position >= in && position <= out ) )
201                 {
202                         if ( !accepts_blanks && ( this->b_frame == NULL || ( mlt_frame_is_test_card( this->b_frame ) && mlt_frame_is_test_audio( this->b_frame ) ) ) )
203                         {
204                                 *frame = this->a_frame;
205                         }
206                         else if ( !accepts_blanks && ( this->a_frame == NULL || ( mlt_frame_is_test_card( this->a_frame ) && mlt_frame_is_test_audio( this->a_frame ) ) ) )
207                         {
208                                 mlt_frame t = this->a_frame;
209                                 this->a_frame = this->b_frame;
210                                 this->b_frame = t;
211                                 *frame = this->a_frame;
212                         }
213                         else
214                         {
215                                 int hide = 0;
216                                 *frame = mlt_transition_process( this, this->a_frame, this->b_frame );
217                                 if ( !mlt_properties_get_int( mlt_frame_properties( this->a_frame ), "test_image" ) )
218                                         hide = 1;
219                                 if ( !mlt_properties_get_int( mlt_frame_properties( this->a_frame ), "test_audio" ) )
220                                         hide |= 2;
221                                 mlt_properties_set_int( mlt_frame_properties( this->b_frame ), "hide", hide );
222                         }
223                         this->a_held = 0;
224                 }
225                 else
226                 {
227                         // Pass on the 'a frame' and remember that we've done it
228                         *frame = this->a_frame;
229                         this->a_held = 0;
230                 }
231                 return 0;
232         }
233         if ( index == b_track )
234         {
235                 // Pass on the 'b frame' and remember that we've done it
236                 *frame = this->b_frame;
237                 this->b_held = 0;
238                 return 0;
239         }
240         else
241         {
242                 // Pass through
243                 return mlt_service_get_frame( this->producer, frame, index );
244         }
245 }
246
247 /** Close the transition.
248 */
249
250 void mlt_transition_close( mlt_transition this )
251 {
252         if ( this != NULL && mlt_properties_dec_ref( mlt_transition_properties( this ) ) <= 0 )
253         {
254                 this->parent.close = NULL;
255                 if ( this->close != NULL )
256                         this->close( this );
257                 else
258                         mlt_service_close( &this->parent );
259         }
260 }