2 * mlt_multitrack.c -- multitrack service class
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_multitrack.h"
24 #include "mlt_frame.h"
29 /** Private definition.
32 struct mlt_multitrack_s
34 // We're extending producer here
35 struct mlt_producer_s parent
;
41 /** Forward reference.
44 static int producer_get_frame( mlt_producer parent
, mlt_frame_ptr frame
, int index
);
49 mlt_multitrack
mlt_multitrack_init( )
51 // Allocate the multitrack object
52 mlt_multitrack
this = calloc( sizeof( struct mlt_multitrack_s
), 1 );
56 mlt_producer producer
= &this->parent
;
57 if ( mlt_producer_init( producer
, this ) == 0 )
59 producer
->get_frame
= producer_get_frame
;
71 /** Get the producer associated to this multitrack.
74 mlt_producer
mlt_multitrack_producer( mlt_multitrack
this )
79 /** Get the service associated this multitrack.
82 mlt_service
mlt_multitrack_service( mlt_multitrack
this )
84 return mlt_producer_service( mlt_multitrack_producer( this ) );
87 /** Get the properties associated this multitrack.
90 mlt_properties
mlt_multitrack_properties( mlt_multitrack
this )
92 return mlt_service_properties( mlt_multitrack_service( this ) );
95 /** Initialise timecode related information.
98 void mlt_multitrack_refresh( mlt_multitrack
this )
102 // Obtain the properties of this multitrack
103 mlt_properties properties
= mlt_multitrack_properties( this );
105 // We need to ensure that the multitrack reports the longest track as its length
106 mlt_timecode length
= 0;
108 // We need to ensure that fps are the same on all services
111 // Obtain stats on all connected services
112 for ( i
= 0; i
< this->count
; i
++ )
114 // Get the producer from this index
115 mlt_producer producer
= this->list
[ i
];
117 // If it's allocated then, update our stats
118 if ( producer
!= NULL
)
120 // Determine the longest length
121 length
= mlt_producer_get_length( producer
) > length ?
mlt_producer_get_length( producer
) : length
;
126 // This is the first producer, so it controls the fps
127 fps
= mlt_producer_get_fps( producer
);
129 else if ( fps
!= mlt_producer_get_fps( producer
) )
131 // Generate a warning for now - the following attempt to fix may fail
132 fprintf( stderr
, "Warning: fps mismatch on track %d\n", i
);
134 // It should be safe to impose fps on an image producer, but not necessarily safe for video
135 mlt_properties_set_double( mlt_producer_properties( producer
), "fps", fps
);
140 // Update multitrack properties now - we'll not destroy the in point here
141 mlt_properties_set_timecode( properties
, "length", length
);
142 mlt_properties_set_timecode( properties
, "out", length
);
143 mlt_properties_set_timecode( properties
, "playtime", length
- mlt_properties_get_timecode( properties
, "in" ) );
144 mlt_properties_set_double( properties
, "fps", fps
);
147 /** Connect a producer to a given track.
150 int mlt_multitrack_connect( mlt_multitrack
this, mlt_producer producer
, int track
)
152 // Connect to the producer to ourselves at the specified track
153 int result
= mlt_service_connect_producer( mlt_multitrack_service( this ), mlt_producer_service( producer
), track
);
157 // Resize the producer list if need be
158 if ( track
>= this->size
)
161 this->list
= realloc( this->list
, ( track
+ 10 ) * sizeof( mlt_producer
) );
162 for ( i
= this->size
; i
< track
+ 10; i
++ )
163 this->list
[ i
] = NULL
;
164 this->size
= track
+ 10;
167 // Assign the track in our list here
168 this->list
[ track
] = producer
;
170 // Increment the track count if need be
171 if ( track
>= this->count
)
172 this->count
= track
+ 1;
175 mlt_multitrack_refresh( this );
181 /** Get frame method.
183 Special case here: The multitrack must be used in a conjunction with a downstream
184 tractor-type service, ie:
187 Producer2 - multitrack - { filters/transitions } - tractor - consumer
190 The get_frame of a tractor pulls frames from it's connected service on all tracks and
191 will terminate as soon as it receives a test card with a last_track property. The
192 important case here is that the mulitrack does not move to the next frame until all
193 tracks have been pulled.
195 Reasoning: In order to seek on a network such as above, the multitrack needs to ensure
196 that all producers are positioned on the same frame. It uses the 'last track' logic
197 to determine when to move to the next frame.
199 Flaw: if a transition is configured to read from a b-track which happens to trigger
200 the last frame logic (ie: it's configured incorrectly), then things are going to go
203 See playlist logic too.
206 static int producer_get_frame( mlt_producer parent
, mlt_frame_ptr frame
, int index
)
208 // Get the mutiltrack object
209 mlt_multitrack
this = parent
->child
;
211 // Check if we have a track for this index
212 if ( index
< this->count
&& this->list
[ index
] != NULL
)
214 // Get the producer for this track
215 mlt_producer producer
= this->list
[ index
];
217 // Obtain the current timecode
218 uint64_t position
= mlt_producer_frame( parent
);
220 // Make sure we're at the same point
221 mlt_producer_seek_frame( producer
, position
);
223 // Get the frame from the producer
224 mlt_service_get_frame( mlt_producer_service( producer
), frame
, 0 );
226 // Indicate speed of this producer
227 mlt_properties producer_properties
= mlt_producer_properties( parent
);
228 double speed
= mlt_properties_get_double( producer_properties
, "speed" );
229 mlt_properties properties
= mlt_frame_properties( *frame
);
230 mlt_properties_set_double( properties
, "speed", speed
);
234 // Generate a test frame
235 *frame
= mlt_frame_init( );
237 // Let tractor know if we've reached the end
238 mlt_properties_set_int( mlt_frame_properties( *frame
), "last_track", index
>= this->count
);
240 // Update timecode on the frame we're creating
241 mlt_frame_set_timecode( *frame
, mlt_producer_position( parent
) );
243 // Move on to the next frame
244 if ( index
>= this->count
)
245 mlt_producer_prepare_next( parent
);
248 mlt_multitrack_refresh( this );
254 /** Close this instance.
257 void mlt_multitrack_close( mlt_multitrack
this )
259 // Close the producer
260 mlt_producer_close( &this->parent
);