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