]> git.sesse.net Git - mlt/blob - docs/mlt++.txt
Use the shared ResourcePool also for ad-hoc EffectChains.
[mlt] / docs / mlt++.txt
1 MLT++
2 -----
3
4         This mlt sub-project provides a C++ wrapping for the MLT library.
5
6 Usage
7 -----
8
9         Use the following definitions in a Makefile to compile and link with mlt++:
10
11                 CXXFLAGS=`pkg-config --cflags mlt-framework` -Wall
12                 LDFLAGS=-lmlt++ `pkg-config --libs mlt-framework`
13
14         Include files for the classes can either be explicitly included, ie:
15
16                 #include <mlt++/MltProducer.h>
17                 etc
18
19         Or you can include all using:
20
21                 #include <mlt++/Mlt.h>
22
23         All definitions are placed in an Mlt namespace, and adhere closely to the C
24         naming convention. Mappings always follow the pattern:
25
26         Factory methods:
27
28                 mlt_factory_init        ==> Mlt::Factory::init
29                 mlt_factory_producer    ==> Mlt::Factory::producer
30                 mlt_factory_filter      ==> Mlt::Factory::filter
31                 mlt_factory_transition  ==> Mlt::Factory::transition
32                 mlt_factory_consumer    ==> Mlt::Factory::consumer
33                 mlt_factory_close       ==> Mlt::Factory::close
34
35         NB: Factory usage for service construction is optional.
36
37         Types:
38
39                 mlt_properties          ==> Mlt::Properties
40                 mlt_frame               ==> Mlt::Frame
41                 mlt_service             ==> Mlt::Service
42                 mlt_producer            ==> Mlt::Producer
43                 mlt_filter              ==> Mlt::Filter
44                 mlt_transition          ==> Mlt::Transition
45                 mlt_consumer            ==> Mlt::Consumer
46
47         Methods:
48
49                 mlt_type_method         ==> Mlt::Type.method
50         ie:     mlt_playlist_append     ==> Mlt::Playlist.append
51
52         Parent methods are available directly on children.
53
54         Additionally, you can specify:
55
56                 using namespace Mlt;
57
58         To avoid the enforced use of the Mlt:: prefix.
59
60         Enumerators and macros are reused directly from the C library.
61
62 Class Hierarchy
63 ---------------
64
65         The currently mapped objects are shown in the following hierarchy:
66
67                 Factory
68                 Properties
69                         Frame
70                         Service
71                                 Consumer
72                                 Field
73                                 Filter
74                                 Multitrack
75                                 Producer
76                                         Playlist
77                                 Tractor
78                                 Transition
79
80 Special Cases
81 -------------
82
83         Care should be taken with wrapper objects. 
84
85         Taking, as an example, the C function that returns the immediate consumer of
86         a service:
87
88                 mlt_service mlt_service_consumer( mlt_service );
89
90         This maps to:
91
92                 Mlt::Service *Mlt::Service.consumer( );
93
94         Note that you get an object back - it is never the original c++ object, but 
95         a wrapping object. This is done to keep consistency with the C api which may 
96         instantiate C instances - therefore it cannot be assumed that a C++ object 
97         exists for all mlt service instances.
98
99         As such, it is mandatory that you delete these objects. The original will 
100         not be affected. However, all other modifications (to properties or its
101         state of connection) will be reflected in the original object.
102
103         This approach excludes the use of RTTI to determine the real type of the 
104         object - this can only be done by parsing the objects properties.
105
106         Objects may be invalid - always use the is_valid method to check validity 
107         before use.
108
109 Limitations
110 -----------
111
112         The mechanisms for the definition of new services are deliberately 
113         excluded from the C++ wrappings - this is done to ensure that service 
114         networks constructed can be serialised and used by existing applications
115         which are based on the C API (such as melted).
116
117 Hello World
118 -----------
119
120         The mlt++ wrapper is a c++ wrapper for the mlt C library. As such, it 
121         provides clean C++ access to the underlying library.
122
123         An example of use is as follows:
124
125             #include <mlt++/Mlt.h>
126             using namespace Mlt;
127
128             int main( void )
129             {
130                 Factory::init( );
131                 Producer p( "pango:", "Hello World" );
132                 Consumer c( "sdl" );
133                 c.connect( p );
134                 c.run( );
135                 return 0;
136             }
137
138         This is a fairly typical example of mlt++ usage - create a 'producer' (an
139         object which produces 'frames'), create a 'consumer' (an object which consumes
140         frames), connect them together, start the consumer and wait until done (here
141         we just wait for the user to close the window).
142
143         In this case, we construct a window as a consumer using the 'sdl' consumer
144         (SDL is a standard portable library which provides platform independent
145         access to accelerated video display and audio) and use the 'pango' 
146         producer to generate frames with the words 'Hello World' (pango is a 
147         library from the gtk toolkit).
148
149         The main point of this example is to show that mlt uses existing libraries
150         to provide its functionality - this keeps the framework itself very small.
151
152         Note that mlt is designed to be housed in GUI or server type applications -
153         typically, applications don't wait around for the consumer to be stopped in
154         the manner shown.
155
156         So far, we've introduced the Producer and Consumer mlt classes. We'll cover
157         each of these in more detail later in the tutorial, but for now, we'll 
158         briefly cover the remaining classes.
159
160
161 Playlists
162 ---------
163
164         Another simple class is the Playlist - this is direct extension of Producer
165         and it allows you to maintain a list of producer objects.
166
167         As a simple example of the Playlist in action, we'll convert the example
168         above into an application which plays multiple video or audio files.
169
170             #include <mlt++/Mlt.h>
171             using namespace Mlt;
172
173             int main( int argc, char **argv )
174             {
175                 Factory::init( );
176                 Playlist list;
177                 for ( int i = 1; i < argc; i ++ )
178                 {
179                     Producer p( argv[i] );
180                     if ( p.is_valid( ) )
181                         list.append( p );
182                 }
183                 Consumer c( "sdl" );
184                 c.connect( list );
185                 c.run( );
186                 return 0;
187             }
188
189         Now you can run the program as:
190
191             ./player *.avi *.mp3 *.jpg etc
192
193         In this case, we construct a playlist by simply appending producers to it.
194         Notice that although the scope of the Producer is limited to the inner 
195         for loop, we can safely add it to the playlist - this is due to the fact
196         that all mlt objects maintain reference counts and no object is really
197         destroyed until all the references are gone. In this case, when the list
198         object goes out of scope, all the producers we created will automatically
199         be destroyed.
200
201
202 Filters
203 -------
204
205         So far, we've shown how you can load and play media. We've given a brief
206         intro to the Playlist container, now it's time to start manipulating 
207         things...
208
209         For the next example, I'll add a 'watermark' to the video - a watermark
210         is used by broadcasters to brand the channel and normally consists of a 
211         logo of some sort. We'll just use some black text on a partially 
212         transparent red background.
213
214         #include <mlt++/Mlt.h>
215         using namespace Mlt;
216
217         int main( int argc, char **argv )
218         {
219             Factory::init( );
220             Playlist list;
221             for ( int i = 1; i < argc; i ++ )
222             {
223                 Producer p( argv[i] );
224                 if ( p.is_valid( ) )
225                     list.append( p );
226             }
227             Filter f( "watermark", "pango:" );
228             f.set( "producer.text", "MLT++" );
229             f.set( "producer.fgcolour", "0x000000ff" );
230             f.set( "producer.bgcolour", "0xff000080" );
231             list.attach( f );
232             Consumer c( "sdl" );
233             c.connect( list );
234             c.run( );
235             return 0;
236         }
237
238         Notice that the watermark filter reuses the 'pango' producer we showed in the
239         first example. In fact, you could use any producer here - if you wanted to
240         use a graphic or a video, you would just construct the filter with a full path
241         to that as the second argument.
242
243         We manipulate the filter using the set method - this method was also shown
244         in the first example. 
245
246         Finally, we attach the filter to the playlist. This ensure that all frames 
247         that are obtained from the playlist are watermarked. 
248
249
250 Cuts
251 ----
252
253         When you add a clip to a playlist, the a cut object is created - this is merely a
254         wrapper for the producer, spanning the specified in and out points. 
255
256         Whenever you retrieve a clip from a playlist, you will always get a cut object.
257         This allows you to attach filters to a specific part of a producer and should
258         the position of the cut in the playlist change, then the filter will remain
259         correctly associated to it.
260
261         A producer and a cut are generally identical in behaviour, but should you need to
262         distinguish between them, you can use:
263
264             if ( producer.is_cut( ) )
265
266         and to retrieve the parent of a cut, you can use:
267
268             Producer parent = producer.parent_cut( );
269
270         Filters that are attached directly to a parent are executed before any filters
271         attached to the cut.
272
273
274 Tractor
275 -------
276
277         A tractor is an object that allows the manipulation of multiple video and audio
278         tracks. 
279
280         Stepping away from the player example we've been tinkering with for a minute,
281         let's assume we want to do something like dub a video with some audio. This
282         a very trivial thing to do:
283
284         Tractor *dub( char *video_file, char *audio_file )
285         {
286             Tractor *tractor = new Tractor( );
287             Producer video( video_file );
288             Producer audio( audio_file );
289             tractor->set_track( video, 0 );
290             tractor->set_track( audio, 1 );
291             return tractor;
292         }
293
294         That's all that needs to be done - you can now connect the returned object to a
295         consumer, or add it to a playlist, or even apply it as a track to another tractor.
296
297
298 Transition
299 ----------
300
301         Let's now assume we want to mix the audio between two tracks - to do this, we 
302         need to introduce the concept of a transition. A transition in mlt is a service
303         which combines frames from two producers to produce a new frame.
304
305         Tractor *mix( char *video_file, char *audio_file )
306         {
307             Tractor *tractor = new Tractor( );
308             Transition mix( "mix" );
309             Producer video( video_file );
310             Producer audio( audio_file );
311             tractor.set_track( video, 0 );
312             tractor.set_track( audio, 1 );
313             tractor.field.plant_transition( mix, 0, 1 );
314             return tractor;
315         }
316
317         The tractor returned will now mix the audio from the original video and the 
318         audio.
319
320
321 Mix
322 ---
323
324         There is a convenience function which simplifies the process of applying 
325         transitions betwee adjacent cuts on a playlist. This is often preferable 
326         to use over the constuction of your own tractor and transition set up.
327
328         To apply a 25 frame luma transition between the first and second cut on 
329         the playlist, you could use:
330
331             Transition luma;
332             playlist.mix( 0, 25, luma );
333
334
335 Events
336 ------
337
338         Typically, applications need to be informed when changes occur in an mlt++ object.
339         This facilitates application services such as undo/redo management, or project
340         rendering in a timeline type widget and many other types of operations which an
341         application needs.
342
343         As an example, consider the following:
344
345             class Xml
346             {
347                 private:
348                     Consumer consumer;
349                     Tractor &tractor;
350                 public:
351                     Xml( MltTractor &tractor ) :
352                         tractor( tractor ),
353                         consumer( "xml" )
354                     {
355                         consumer.connect( tractor );
356                         tractor.listen( tractor, "producer-changed", 
357                                         ( mlt_listener )Xml::listener );
358                     }
359                     
360                     static void listener( Properties *tractor, Xml *object )
361                     {
362                         object->activate( );
363                     }
364         
365                     void activate( )
366                     {
367                         consumer.start( );
368                     }
369             };
370
371         Now, each time the tractor is changed, the XML representation is output to 
372         stderr.
373
374
375 That's All Folks...
376 -------------------
377
378         And that, believe it or not, is a fairly complete summary of the classes you'll 
379         typically be interfacing with in mlt++. Obviously, there's a little more to it 
380         than this - a couple of intrisinc classes have been glossed over (notably, the 
381         Properties and Service base classes). The next section will cover all of the 
382         above, but in much more detail...
383
384
385 DIGGING DEEPER
386 --------------
387
388         The previous section was designed to give you a whistle stop tour through the major
389         framework classes. This section will take you through the scenic route.
390
391
392 Introducing Base Classes
393 ------------------------
394
395         Services in mlt are the collective noun for Producers, Filters, Transitions and 
396         Consumer. A Service is also the base class from which all of these classes 
397         extend. It provides the basic connectivity which has been shown throughout the
398         examples in the previous section.
399
400         Properties are the main way in which we communicate with the Services - 
401         essentially, it provides get/set methods for named values. All services extend
402         Properties.
403
404
405 Properties
406 ----------
407
408         Properties provide the general mechanism for communicating with Services - 
409         through the Properties interface, we are able to manipulate and serialise 
410         a services state.
411
412         For example, to dump all the properties to stdout, you can use something 
413         like:
414
415         void dump( Properties &properties )
416         {
417             for ( int i = 0; i < properties.count( ); i ++ )
418                 cout << Properties.get_name( i ) << " = " << Properties.get( i ) << endl;
419         }
420
421         Note that the properties object handles type conversion, so the following
422         is acceptable:
423
424         properties.set( "hello", "10.5" );
425         int hello_int = properties.get_int( "hello" );
426         double hello_double = properties.get_double( "hello" );
427
428         A couple of convenience methods are provide to examine or serialise property
429         objects. 
430
431         For example:
432
433         properties.debug( );
434
435         will report all serialisable properties on stderr, in the form:
436
437         Object: [ ref=1, in=0, out=0, track=0, u=75, v=150, _unique_id=15, 
438         mlt_type=filter, mlt_service=sepia ]
439
440
441 Services
442 --------
443
444         Typically, all the services are constructed via the specific classes 
445         constructor. Often, you will receive Service objects rather than their
446         specific type. In order to access the extended classes interface, 
447         you will need to create a reference.
448
449         For example, given an arbitrary Service object, you can determine its
450         type by using the type method - this will return a 'service_type' which
451         has values of producer_type, filter_type etc. Alternatively, you can
452         create a wrapping object and check on its validity.
453
454         bool do_we_have_a_producer( Service &service )
455         {
456             Producer producer( service );
457             return producer.is_valid( );
458         }
459
460
461 Events
462 ------
463
464
465 Servers and MLT XML Docs
466 ------------------------
467
468         For various reasons, you might want to serialise a producer to a string.
469         To do this, you just need to specify a property to write to:
470
471             Consumer xml( "xml", "buffer" );
472             xml.connect( producer );
473             xml.start( );
474             buffer = xml.get( "buffer" );
475
476         You can use any name you want, and you can change it using the "resource"
477         property. Any name with a '.' in it is considered to be a file. Hence, you
478         can use a xml consumer to store multiple instances of the same MLT 
479         object - useful if you want to provide undo/redo capabilities in an
480         editing application.
481
482         Should you receive an XML document as a string, and you want to send it
483         on to a server, you can use:
484
485             Consumer client( "mvsp", "localhost:5250" );
486             client.set( "xml", buffer );
487             client.start( );
488
489         If you need to obtain an MLT object from a XML string:
490
491             Producer producer( "xml-string", buffer );
492     
493         The following shows a working example of an extended server:
494
495             class ShotcutServer : public Melted
496             {
497                 public:
498                     ShotcutServer( char *id, int port ) :
499                         Melted( id, port )
500                     {
501                     }
502     
503                     void set_receive_doc( bool doc )
504                     {
505                         set( "push-parser-off", doc );
506                     }
507
508                     // Reject all commands other than push/receive
509                     Response *execute( char *command )
510                     {
511                         mvsp_response response = mvsp_response_init( );
512                         mvsp_response_set_error( response, 400, "Not OK" );
513                         return new Response( response );
514                     }
515         
516                     // Push document handler
517                     Response *received( char *command, char *doc )
518                     {
519                         mvsp_response response = mvsp_response_init( );
520                         // Use doc in some way and assign Response
521                         if ( doc != NULL )
522                             mvsp_response_set_error( response, 200, "OK" );
523                         return new Response( response );
524                     }
525
526                     // Push service handler
527                     Response *push( char *command, Service *service )
528                     {
529                         mvsp_response response = mvsp_response_init( );
530                         // Use service in some way and assign Response
531                         if ( service != NULL )
532                             mvsp_response_set_error( response, 200, "OK" );
533                         return new Response( response );
534                     }
535             };
536
537         NB: Should you be incorporating this into a GUI application, remember that the
538         execute, received and push methods are invoked from a thread - make sure that 
539         you honour the locking requirements of your GUI toolkit before interacting with
540         the UI.
541
542