Improved push capabilities
[melted] / mlt++ / HOWTO
1 INTRODUCTION
2 ------------
3
4         This document provides a brief tutorial on the use of the mlt++ wrapper 
5         and bindings.
6
7
8 Hello World
9 -----------
10
11         The mlt++ wrapper is a c++ wrapper for the mlt C library. As such, it 
12         provides clean C++ access to the underlying library.
13
14         An example of use is as follows:
15
16         #include <mlt++/Mlt.h>
17         using namespace Mlt;
18
19         int main( void )
20         {
21                 Factory::init( );
22                 Producer p( "pango:" );
23                 p.set( "text", "Hello World" );
24                 Consumer c( "sdl" );
25                 Event *e = c.setup_wait_for( "consumer-stopped" );
26                 c.connect( p );
27                 c.start( );
28                 c.wait_for( e );
29                 delete e;
30                 return 0;
31         }
32
33         This is a fairly typical example of use of mlt++ - create a 'producer' (an
34         object which produces 'frames'), create a 'consumer' (an object which consumes
35         frames), connect them together, start the consumer and wait until done (here
36         we just wait for the user to close the window).
37
38         In this case, we construct a window as a consumer using the 'sdl' consumer
39         (SDL is a standard portable library which provides platform independent
40         access to accelerated video display and audio) and use the 'pango' 
41         producer to generate frames with the words 'Hello World' (pango is a 
42         library from the gtk toolkit).
43
44         The main point of this example is to show that mlt uses existing libraries
45         to provide its functionality - this keeps the framework itself very small.
46
47         Note that mlt is designed to be housed in GUI or server type applications -
48         typically, applications don't wait around for the consumer to be stopped in
49         the manner shown.
50
51         So far, we've introduced the Producer and Consumer mlt classes. We'll cover
52         each of these in more detail later in the tutorial, but for now, we'll 
53         briefly cover the remaining classes.
54
55
56 Playlists
57 ---------
58
59         Another simple class is the Playlist - this is direct extension of Producer
60         and it allows you to maintain a list of producer objects.
61
62         As a simple example of the Playlist in action, we'll convert the example
63         above into an application which plays multiple video or audio files.
64
65         #include <mlt++/Mlt.h>
66         using namespace Mlt;
67
68         int main( int argc, char **argv )
69         {
70                 Factory::init( );
71                 Playlist list;
72                 for ( int i = 1; i < argc; i ++ )
73                 {
74                         Producer p( argv[i] );
75                         if ( p.is_valid( ) )
76                                 list.append( p );
77                 }
78                 Consumer c( "sdl" );
79                 c.connect( list );
80                 Event *e = c.setup_wait_for( "consumer-stopped" );
81                 c.start( );
82                 c.wait_for( e );
83                 delete e;
84                 return 0;
85         }
86
87         Now you can run the program as:
88
89                 ./player *.avi *.mp3 *.jpg etc
90
91         In this case, we construct a playlist by simply appending producers to it.
92         Notice that although the scope of the Producer is limited to the inner 
93         for loop, we can safely add it to the playlist - this is due to the fact
94         that all mlt objects maintain reference counts and no object is really
95         destroyed until all the references are gone. In this case, when the list
96         object goes out of scope, all the producers we created will automatically
97         be destroyed.
98
99
100 Filters
101 -------
102
103         So far, we've shown how you can load and play media. We've given a brief
104         intro to the Playlist container, now it's time to start manipulating 
105         things...
106
107         For the next example, I'll add a 'watermark' to the video - a watermark
108         is used by broadcasters to brand the channel and normally consists of a 
109         logo of some sort. We'll just use some black text on a partially 
110         transparent red background.
111
112         #include <mlt++/Mlt.h>
113         using namespace Mlt;
114
115         int main( int argc, char **argv )
116         {
117                 Factory::init( );
118                 Playlist list;
119                 for ( int i = 1; i < argc; i ++ )
120                 {
121                         Producer p( argv[i] );
122                         if ( p.is_valid( ) )
123                                 list.append( p );
124                 }
125                 Filter f( "watermark", "pango:" );
126                 f.set( "producer.text", "MLT++" );
127                 f.set( "producer.fgcolour", "0x000000ff" );
128                 f.set( "producer.bgcolour", "0xff000080" );
129                 list.attach( f );
130                 Consumer c( "sdl" );
131                 c.connect( list );
132                 Event *e = c.setup_wait_for( "consumer-stopped" );
133                 c.start( );
134                 c.wait_for( e );
135                 delete e;
136                 return 0;
137         }
138
139         Notice that the watermark filter reuses the 'pango' producer we showed in the
140         first example. In fact, you could use any producer here - if you wanted to
141         use a graphic or a video, you would just construct the filter with a full path
142         to that as the second argument.
143
144         We manipulate the filter using the set method - this method was also shown
145         in the first example. 
146
147         Finally, we attach the filter to the playlist. This ensure that all frames 
148         that are obtained from the playlist are watermarked. 
149
150
151 Tractor
152 -------
153
154         A tractor is an object that allows the manipulation of multiple video and audio
155         tracks. 
156
157         Stepping away from the player example we've been tinkering with for a minute,
158         let's assume we want to do something like dubbing a video with some audio. This
159         a very trivial thing to do:
160
161         Tractor *dub( char *video_file, char *audio_file )
162         {
163                 Tractor *tractor = new Tractor( );
164                 Producer video( video_file );
165                 Producer audio( audio_file );
166                 tractor->set_track( video, 0 );
167                 tractor->set_track( audio, 1 );
168                 return tractor;
169         }
170
171         That's all that needs to be done - you can now connect the returned object to a
172         consumer, or add it to a playlist, or even apply it as a track to another tractor.
173
174
175 Transition
176 ----------
177
178         Let's now assume we want to mix the audio between two tracks - to do this, we 
179         need to introduce the concept of a transition. A transition in mlt is a service
180         which combines frames from two producers to produce a new frame.
181
182         Tractor *mix( char *video_file, char *audio_file )
183         {
184                 Tractor *tractor = new Tractor( );
185                 Transition mix( "mix" );
186                 Producer video( video_file );
187                 Producer audio( audio_file );
188                 tractor.set_track( video, 0 );
189                 tractor.set_track( audio, 1 );
190                 tractor.field.plant_transition( mix, 0, 1 );
191                 return tractor;
192         }
193
194         The tractor returned will now mix the audio from the original video and the audio.
195
196
197 Events
198 ------
199
200         Typically, applications need to be informed when changes occur in an mlt++ object.
201         This facilitates application services such as undo/redo management, or project
202         rendering in a timeline type widget and many other types of operations which an
203         application needs.
204
205         As an example, consider the following:
206
207         class Westley
208         {
209                 private:
210                         Consumer consumer;
211                         Tractor &tractor;
212                 public:
213                         Westley( MltTractor &tractor ) :
214                                 tractor( tractor ),
215                                 consumer( "westley" )
216                         {
217                                 consumer.connect( tractor );
218                                 tractor.listen( tractor, "producer-changed", ( mlt_listener )Westley::listener );
219                         }
220                         
221                         static void listener( Properties *tractor, Westley *object )
222                         {
223                                 object->activate( );
224                         }
225
226                         void activate( )
227                         {
228                                 consumer.start( );
229                         }
230         };
231
232         
233
234 That's All Folks...
235 -------------------
236
237         And that, believe it or not, is a fairly complete summary of the classes you'll 
238         typically be interfacing with in mlt++. Obviously, there's a little more to it 
239         than this - a couple of intrisinc classes have been glossed over (notably, the 
240         Properties and Service base classes). The next section will cover all of the 
241         above, but in much more detail...
242
243
244 DIGGING DEEPER
245 --------------
246
247         The previous section was designed to give you a whistle stop tour through the major
248         framework classes. This section will take you through the scenic route.
249
250
251 Introducing Base Classes
252 ------------------------
253
254         Services in mlt are the collective noun for Producers, Filters, Transitions and 
255         Consumer. A Service is also the base class from which all of these classes 
256         extend. It provides the basic connectivity which has been shown throughout the
257         examples in the previous section.
258
259         Properties are the main way in which we communicate with the Services - 
260         essentially, it provides get/set methods for named values. All services extend
261         Properties.
262
263
264 Properties
265 ----------
266
267         Properties provide the general mechanism for communicating with Services - 
268         through the Properties interface, we are able to manipulate and serialise 
269         a services state.
270
271         For example, to dump all the properties to stdout, you can use something 
272         like:
273
274         void dump( Properties &properties )
275         {
276                 for ( int i = 0; i < properties.count( ); i ++ )
277                         cout << Properties.get_name( i ) << " = " << Properties.get( i ) << endl;
278         }
279
280         Note that the properties object handles type conversion, so the following
281         is acceptable:
282
283         properties.set( "hello", "10.5" );
284         int hello_int = properties.get_int( "hello" );
285         double hello_double = properties.get_double( "hello" );
286
287         A couple of convenience methods are provide to examine or serialise property
288         objects. 
289
290         For example:
291
292         properties.debug( );
293
294         will report all serialisable properties on stderr, in the form:
295
296         Object: [ ref=1, in=0, out=0, track=0, u=75, v=150, _unique_id=15, 
297         mlt_type=filter, mlt_service=sepia ]
298
299
300 Services
301 --------
302
303         Typically, all the services are constructed via the specific classes 
304         constructor. Often, you will receive Service objects rather than their
305         specific type. In order to access the extended classes interface, 
306         you will need to create a reference.
307
308         For example, given an arbitrary Service object, you can determine its
309         type by using the type method - this will return a 'service_type' which
310         has values of producer_type, filter_type etc. Alternatively, you can
311         create a wrapping object and check on its validity.
312
313         bool do_we_have_a_producer( Service &service )
314         {
315                 Producer producer( service );
316                 return producer.is_valid( );
317         }
318
319
320 Events
321 ------