From 0caa0a91b0971439dfe00d0ed9bc05992b7dd609 Mon Sep 17 00:00:00 2001 From: lilo_booter Date: Tue, 31 Aug 2004 08:35:19 +0000 Subject: [PATCH] Run time type identification git-svn-id: https://mlt.svn.sourceforge.net/svnroot/mlt/trunk/mlt++@402 d19143bc-622f-0410-bfdd-b5b2a6649095 --- mlt++/HOWTO | 287 +++++++++++++++++++++++++++++++++++++++++++ mlt++/src/Makefile | 2 +- mlt++/src/MltConsumer.cpp | 10 ++ mlt++/src/MltConsumer.h | 1 + mlt++/src/MltFilter.cpp | 10 ++ mlt++/src/MltFilter.h | 1 + mlt++/src/MltFrame.cpp | 4 + mlt++/src/MltFrame.h | 1 + mlt++/src/MltMultitrack.cpp | 10 ++ mlt++/src/MltMultitrack.h | 2 + mlt++/src/MltPlaylist.cpp | 14 ++- mlt++/src/MltPlaylist.h | 2 +- mlt++/src/MltProducer.cpp | 12 ++ mlt++/src/MltProducer.h | 1 + mlt++/src/MltService.cpp | 34 +++++ mlt++/src/MltService.h | 15 +++ mlt++/src/MltTractor.cpp | 10 ++ mlt++/src/MltTractor.h | 3 +- mlt++/src/MltTransition.cpp | 10 ++ mlt++/src/MltTransition.h | 1 + 20 files changed, 422 insertions(+), 8 deletions(-) create mode 100644 mlt++/HOWTO diff --git a/mlt++/HOWTO b/mlt++/HOWTO new file mode 100644 index 0000000..830ab29 --- /dev/null +++ b/mlt++/HOWTO @@ -0,0 +1,287 @@ +INTRODUCTION +------------ + + This document provides a brief tutorial on the use of the mlt++ wrapper + and bindings. + + +Hello World +----------- + + The mlt++ wrapper is a c++ wrapper for the mlt C library. As such, it + provides clean C++ access to the underlying library. + + An example of use is as follows: + + #include + #include + using namespace Mlt; + + int main( void ) + { + Factory::init( ); + Producer p( "pango:" ); + p.set( "text", "Hello World" ); + Consumer c( "sdl" ); + c.connect( p ); + c.start( ); + struct timespec tm = { 1, 0 }; + while ( !c.is_stopped( ) ) + nanosleep( &tm, NULL ); + return 0; + } + + This is a fairly typical example of use of mlt++ - create a 'producer' (an + object which produces 'frames'), create a 'consumer' (an object which consumes + frames), connect them together, start the consumer and wait until done (here + we just wait for the user to close the window). + + In this case, we construct a window as a consumer using the 'sdl' consumer + (SDL is a standard portable library which provides platform independent + access to accelerated video display and audio) and use the 'pango' + producer to generate frames with the words 'Hello World' (pango is a + library from the gtk toolkit). + + The main point of this example is to show that mlt uses existing libraries + to provide its functionality - this keeps the framework itself very small. + + Note that mlt is designed to be housed in GUI or server type applications - + typically, applications don't wait around for the consumer to be stopped in + the manner shown. + + TODO: Replace wait loop with an event. + + So far, we've introduced the Producer and Consumer mlt classes. We'll cover + each of these in more detail later in the tutorial, but for now, we'll + briefly cover the remaining classes. + + +Playlists +--------- + + Another simple class is the Playlist - this is direct extension of Producer + and it allows you to maintain a list of producer objects. + + As a simple example of the Playlist in action, we'll convert the example + above into an application which plays multiple video or audio files. + + #include + #include + using namespace Mlt; + + int main( int argc, char **argv ) + { + Factory::init( ); + Playlist list; + for ( int i = 1; i < argc; i ++ ) + { + Producer p( argv[i] ); + if ( p.is_valid( ) ) + list.append( p ); + } + Consumer c( "sdl" ); + c.connect( list ); + c.start( ); + struct timespec tm = { 1, 0 }; + while ( !c.is_stopped( ) ) + nanosleep( &tm, NULL ); + return 0; + } + + Now you can run the program as: + + ./player *.avi *.mp3 *.jpg etc + + In this case, we construct a playlist by simply appending producers to it. + Notice that although the scope of the Producer is limited to the inner + for loop, we can safely add it to the playlist - this is due to the fact + that all mlt objects maintain reference counts and no object is really + destroyed until all the references are gone. In this case, when the list + object goes out of scope, all the producers we created will automatically + be destroyed. + + +Filters +------- + + So far, we've shown how you can load and play media. We've given a brief + intro to the Playlist container, now it's time to start manipulating + things... + + For the next example, I'll add a 'watermark' to the video - a watermark + is used by broadcasters to brand the channel and normally consists of a + logo of some sort. We'll just use some black text on a partially + transparent red background. + + #include + #include + using namespace Mlt; + + int main( int argc, char **argv ) + { + Factory::init( ); + Playlist list; + for ( int i = 1; i < argc; i ++ ) + { + Producer p( argv[i] ); + if ( p.is_valid( ) ) + list.append( p ); + } + Filter f( "watermark", "pango:" ); + f.set( "producer.text", "MLT++" ); + f.set( "producer.fgcolour", "0x000000ff" ); + f.set( "producer.bgcolour", "0xff000080" ); + list.attach( f ); + Consumer c( "sdl" ); + c.connect( list ); + c.start( ); + struct timespec tm = { 1, 0 }; + while ( !c.is_stopped( ) ) + nanosleep( &tm, NULL ); + return 0; + } + + Notice that the watermark filter reuses the 'pango' producer we showed in the + first example. In fact, you could use any producer here - if you wanted to + use a graphic or a video, you would just construct the filter with a full path + to that as the second argument. + + We manipulate the filter using the set method - this method was also shown + in the first example. + + Finally, we attach the filter to the playlist. This ensure that all frames + that are obtained from the playlist are watermarked. + + +Tractor +------- + + A tractor is an object that allows the manipulation of multiple video and audio + tracks. + + Stepping away from the player example we've been tinkering with for a minute, + let's assume we want to do something like dubbing a video with some audio. This + a very trivial thing to do: + + Tractor *dub( char *video_file, char *audio_file ) + { + Tractor *tractor = new Tractor( ); + Producer video( video_file ); + Producer audio( audio_file ); + tractor->set_track( video, 0 ); + tractor->set_track( audio, 1 ); + return tractor; + } + + That's all that needs to be done - you can now connect the returned object to a + consumer, or add it to a playlist, or even apply it as a track to another tractor. + + +Transition +---------- + + Let's now assume we want to mix the audio between two tracks - to do this, we + need to introduce the concept of a transition. A transition in mlt is a service + which combines frames from two producers to produce a new frame. + + Tractor *mix( char *video_file, char *audio_file ) + { + Tractor *tractor = new Tractor( ); + Transition mix( "mix" ); + Producer video( video_file ); + Producer audio( audio_file ); + tractor.set_track( video, 0 ); + tractor.set_track( audio, 1 ); + tractor.field.plant_transition( mix, 0, 1 ); + return tractor; + } + + The tractor returned will now mix the audio from the original video and the audio. + + +That's All Folks... +------------------- + + And that, believe it or not, is a fairly complete summary of the classes you'll + typically be interfacing with in mlt++. Obviously, there's a little more to it + than this - a couple of intrisinc classes have been glossed over (notably, the + Properties and Service base classes). The next section will cover all of the + above, but in much more detail... + + +DIGGING DEEPER +-------------- + + The previous section was designed to give you a whistle stop tour through the major + framework classes. This section will take you through the scenic route. + + +Introducing Base Classes +------------------------ + + Services in mlt are the collective noun for Producers, Filters, Transitions and + Consumer. A Service is also the base class from which all of these classes + extend. It provides the basic connectivity which has been shown throughout the + examples in the previous section. + + Properties are the main way in which we communicate with the Services - + essentially, it provides get/set methods for named values. All services extend + Properties. + + +Properties +---------- + + Properties provide the general mechanism for communicating with Services - + through the Properties interface, we are able to manipulate and serialise + a services state. + + For example, to dump all the properties to stdout, you can use something + like: + + void dump( Properties &properties ) + { + for ( int i = 0; i < properties.count( ); i ++ ) + cout << Properties.get_name( i ) << " = " << Properties.get( i ) << endl; + } + + Note that the properties object handles type conversion, so the following + is acceptable: + + properties.set( "hello", "10.5" ); + int hello_int = properties.get_int( "hello" ); + double hello_double = properties.get_double( "hello" ); + + A couple of convenience methods are provide to examine or serialise property + objects. + + For example: + + properties.debug( ); + + will report all serialisable properties on stderr, in the form: + + Object: [ ref=1, in=0, out=0, track=0, u=75, v=150, _unique_id=15, + mlt_type=filter, mlt_service=sepia ] + + +Services +-------- + + Typically, all the services are constructed via the specific classes + constructor. Often, you will receive Service objects rather than their + specific type. In order to access the extended classes interface, + you will need to create a reference. + + For example, given an arbitrary Service object, you can determine its + type by using the type method - this will return a 'service_type' which + has values of producer_type, filter_type etc. Alternatively, you can + create a wrapping object and check on its validity. + + bool do_we_have_a_producer( Service &service ) + { + Producer producer( service ); + return producer.is_valid( ); + } + + diff --git a/mlt++/src/Makefile b/mlt++/src/Makefile index bd8ae66..38d26a7 100644 --- a/mlt++/src/Makefile +++ b/mlt++/src/Makefile @@ -1,5 +1,5 @@ include ../config.mak -CXXFLAGS = -Wall -pthread `mlt-config --cflags` +CXXFLAGS = -Wall -fPIC -DPIC -pthread `mlt-config --cflags` LDFLAGS = `mlt-config --libs` INSTALL = install diff --git a/mlt++/src/MltConsumer.cpp b/mlt++/src/MltConsumer.cpp index c882d4b..657c816 100644 --- a/mlt++/src/MltConsumer.cpp +++ b/mlt++/src/MltConsumer.cpp @@ -47,6 +47,16 @@ Consumer::Consumer( char *id, char *arg ) : } } +Consumer::Consumer( Service &consumer ) : + instance( NULL ) +{ + if ( consumer.type( ) == consumer_type ) + { + instance = ( mlt_consumer )consumer.get_service( ); + inc_ref( ); + } +} + Consumer::Consumer( Consumer &consumer ) : instance( consumer.get_consumer( ) ) { diff --git a/mlt++/src/MltConsumer.h b/mlt++/src/MltConsumer.h index eb12d68..96d3c33 100644 --- a/mlt++/src/MltConsumer.h +++ b/mlt++/src/MltConsumer.h @@ -35,6 +35,7 @@ namespace Mlt mlt_consumer instance; public: Consumer( char *id, char *service = NULL ); + Consumer( Service &consumer ); Consumer( Consumer &consumer ); Consumer( mlt_consumer consumer ); virtual ~Consumer( ); diff --git a/mlt++/src/MltFilter.cpp b/mlt++/src/MltFilter.cpp index 7842f55..90a178e 100644 --- a/mlt++/src/MltFilter.cpp +++ b/mlt++/src/MltFilter.cpp @@ -47,6 +47,16 @@ Filter::Filter( char *id, char *arg ) : } } +Filter::Filter( Service &filter ) : + instance( NULL ) +{ + if ( filter.type( ) == filter_type ) + { + instance = ( mlt_filter )filter.get_service( ); + inc_ref( ); + } +} + Filter::Filter( Filter &filter ) : instance( filter.get_filter( ) ) { diff --git a/mlt++/src/MltFilter.h b/mlt++/src/MltFilter.h index b659965..ac0a720 100644 --- a/mlt++/src/MltFilter.h +++ b/mlt++/src/MltFilter.h @@ -35,6 +35,7 @@ namespace Mlt mlt_filter instance; public: Filter( char *id, char *service = NULL ); + Filter( Service &filter ); Filter( Filter &filter ); Filter( mlt_filter filter ); virtual ~Filter( ); diff --git a/mlt++/src/MltFrame.cpp b/mlt++/src/MltFrame.cpp index 59af257..dc242f4 100644 --- a/mlt++/src/MltFrame.cpp +++ b/mlt++/src/MltFrame.cpp @@ -76,4 +76,8 @@ int16_t *Frame::get_audio( mlt_audio_format &format, int &frequency, int &channe return audio; } +unsigned char *Frame::get_waveform( int w, int h ) +{ + return mlt_frame_get_waveform( get_frame( ), w, h ); +} diff --git a/mlt++/src/MltFrame.h b/mlt++/src/MltFrame.h index 7cd2854..f54fd44 100644 --- a/mlt++/src/MltFrame.h +++ b/mlt++/src/MltFrame.h @@ -41,6 +41,7 @@ namespace Mlt uint8_t *get_image( mlt_image_format &format, int &w, int &h, int writable = 0 ); unsigned char *fetch_image( mlt_image_format format, int w, int h, int writable = 0 ); int16_t *get_audio( mlt_audio_format &format, int &frequency, int &channels, int &samples ); + unsigned char *get_waveform( int w, int h ); }; } diff --git a/mlt++/src/MltMultitrack.cpp b/mlt++/src/MltMultitrack.cpp index fbd9f24..580e79e 100644 --- a/mlt++/src/MltMultitrack.cpp +++ b/mlt++/src/MltMultitrack.cpp @@ -28,6 +28,16 @@ Multitrack::Multitrack( mlt_multitrack multitrack ) : inc_ref( ); } +Multitrack::Multitrack( Service &multitrack ) : + instance( NULL ) +{ + if ( multitrack.type( ) == multitrack_type ) + { + instance = ( mlt_multitrack )multitrack.get_service( ); + inc_ref( ); + } +} + Multitrack::Multitrack( Multitrack &multitrack ) : instance( multitrack.get_multitrack( ) ) { diff --git a/mlt++/src/MltMultitrack.h b/mlt++/src/MltMultitrack.h index 52588ee..5d43468 100644 --- a/mlt++/src/MltMultitrack.h +++ b/mlt++/src/MltMultitrack.h @@ -27,6 +27,7 @@ namespace Mlt { + class Service; class Producer; class Multitrack : public Producer @@ -35,6 +36,7 @@ namespace Mlt mlt_multitrack instance; public: Multitrack( mlt_multitrack multitrack ); + Multitrack( Service &multitrack ); Multitrack( Multitrack &multitrack ); virtual ~Multitrack( ); mlt_multitrack get_multitrack( ); diff --git a/mlt++/src/MltPlaylist.cpp b/mlt++/src/MltPlaylist.cpp index f81fd6e..88d19f1 100644 --- a/mlt++/src/MltPlaylist.cpp +++ b/mlt++/src/MltPlaylist.cpp @@ -50,14 +50,18 @@ Playlist::Playlist( ) : instance = mlt_playlist_init( ); } -Playlist::Playlist( Playlist &playlist ) : - instance( playlist.get_playlist( ) ) +Playlist::Playlist( Service &producer ) : + instance( NULL ) { - inc_ref( ); + if ( producer.type( ) == playlist_type ) + { + instance = ( mlt_playlist )producer.get_service( ); + inc_ref( ); + } } -Playlist::Playlist( Producer &producer ) : - instance( (mlt_playlist )producer.get_producer( ) ) +Playlist::Playlist( Playlist &playlist ) : + instance( playlist.get_playlist( ) ) { inc_ref( ); } diff --git a/mlt++/src/MltPlaylist.h b/mlt++/src/MltPlaylist.h index 904f6cd..7a6e175 100644 --- a/mlt++/src/MltPlaylist.h +++ b/mlt++/src/MltPlaylist.h @@ -54,9 +54,9 @@ namespace Mlt mlt_playlist instance; public: Playlist( ); + Playlist( Service &playlist ); Playlist( Playlist &playlist ); Playlist( mlt_playlist playlist ); - Playlist( Producer &producer ); virtual ~Playlist( ); virtual mlt_playlist get_playlist( ); mlt_producer get_producer( ); diff --git a/mlt++/src/MltProducer.cpp b/mlt++/src/MltProducer.cpp index a12c1da..96d9017 100644 --- a/mlt++/src/MltProducer.cpp +++ b/mlt++/src/MltProducer.cpp @@ -36,6 +36,18 @@ Producer::Producer( char *id, char *service ) : instance = mlt_factory_producer( "fezzik", id != NULL ? id : service ); } +Producer::Producer( Service &producer ) : + instance( NULL ) +{ + service_type type = producer.type( ); + if ( type == producer_type || type == playlist_type || + type == tractor_type || type == multitrack_type ) + { + instance = ( mlt_producer )producer.get_service( ); + inc_ref( ); + } +} + Producer::Producer( mlt_producer producer ) : instance( producer ) { diff --git a/mlt++/src/MltProducer.h b/mlt++/src/MltProducer.h index 3c85fd9..d3b0f44 100644 --- a/mlt++/src/MltProducer.h +++ b/mlt++/src/MltProducer.h @@ -37,6 +37,7 @@ namespace Mlt public: Producer( ); Producer( char *id, char *service = NULL ); + Producer( Service &producer ); Producer( mlt_producer producer ); Producer( Producer &producer ); virtual ~Producer( ); diff --git a/mlt++/src/MltService.cpp b/mlt++/src/MltService.cpp index c7b11d5..3ffbb2d 100644 --- a/mlt++/src/MltService.cpp +++ b/mlt++/src/MltService.cpp @@ -18,6 +18,7 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include #include "MltService.h" using namespace Mlt; @@ -78,3 +79,36 @@ Frame *Service::get_frame( int index ) return new Frame( frame ); } +service_type Service::type( ) +{ + service_type type = invalid_type; + if ( is_valid( ) ) + { + char *mlt_type = get( "mlt_type" ); + char *resource = get( "resource" ); + if ( mlt_type == NULL ) + type = unknown_type; + else if ( !strcmp( mlt_type, "producer" ) ) + type = producer_type; + else if ( !strcmp( mlt_type, "mlt_producer" ) ) + { + if ( resource == NULL ) + type = producer_type; + else if ( !strcmp( resource, "" ) ) + type = playlist_type; + else if ( !strcmp( resource, "" ) ) + type = tractor_type; + else if ( !strcmp( resource, "" ) ) + type = multitrack_type; + } + else if ( !strcmp( mlt_type, "filter" ) ) + type = filter_type; + else if ( !strcmp( mlt_type, "transition" ) ) + type = transition_type; + else if ( !strcmp( mlt_type, "consumer" ) ) + type = consumer_type; + else + type = unknown_type; + } + return type; +} diff --git a/mlt++/src/MltService.h b/mlt++/src/MltService.h index 297f954..9aef193 100644 --- a/mlt++/src/MltService.h +++ b/mlt++/src/MltService.h @@ -31,6 +31,20 @@ namespace Mlt class Properties; class Frame; + enum service_type + { + invalid_type, + unknown_type, + producer_type, + playlist_type, + tractor_type, + multitrack_type, + filter_type, + transition_type, + consumer_type, + field_type + }; + class Service : public Properties { private: @@ -46,6 +60,7 @@ namespace Mlt Service *consumer( ); Service *producer( ); Frame *get_frame( int index = 0 ); + service_type type( ); }; } diff --git a/mlt++/src/MltTractor.cpp b/mlt++/src/MltTractor.cpp index bb6a449..8187a28 100644 --- a/mlt++/src/MltTractor.cpp +++ b/mlt++/src/MltTractor.cpp @@ -28,6 +28,16 @@ Tractor::Tractor( ) : { } +Tractor::Tractor( Service &tractor ) : + instance( NULL ) +{ + if ( tractor.type( ) == tractor_type ) + { + instance = ( mlt_tractor )tractor.get_service( ); + inc_ref( ); + } +} + Tractor::Tractor( mlt_tractor tractor ) : instance( tractor ) { diff --git a/mlt++/src/MltTractor.h b/mlt++/src/MltTractor.h index 6b78435..dc5d20f 100644 --- a/mlt++/src/MltTractor.h +++ b/mlt++/src/MltTractor.h @@ -37,8 +37,9 @@ namespace Mlt mlt_tractor instance; public: Tractor( ); + Tractor( Service &tractor ); Tractor( mlt_tractor tractor ); - Tractor( Tractor &Tractor ); + Tractor( Tractor &tractor ); virtual ~Tractor( ); mlt_tractor get_tractor( ); mlt_producer get_producer( ); diff --git a/mlt++/src/MltTransition.cpp b/mlt++/src/MltTransition.cpp index 4ef08a5..e26feba 100644 --- a/mlt++/src/MltTransition.cpp +++ b/mlt++/src/MltTransition.cpp @@ -47,6 +47,16 @@ Transition::Transition( char *id, char *arg ) : } } +Transition::Transition( Service &transition ) : + instance( NULL ) +{ + if ( transition.type( ) == transition_type ) + { + instance = ( mlt_transition )transition.get_service( ); + inc_ref( ); + } +} + Transition::Transition( Transition &transition ) : instance( transition.get_transition( ) ) { diff --git a/mlt++/src/MltTransition.h b/mlt++/src/MltTransition.h index 6b3c769..dbf61bd 100644 --- a/mlt++/src/MltTransition.h +++ b/mlt++/src/MltTransition.h @@ -34,6 +34,7 @@ namespace Mlt mlt_transition instance; public: Transition( char *id, char *arg = NULL ); + Transition( Service &transition ); Transition( Transition &transition ); Transition( mlt_transition transition ); virtual ~Transition( ); -- 1.7.4.4