Run time type identification
authorlilo_booter <lilo_booter@d19143bc-622f-0410-bfdd-b5b2a6649095>
Tue, 31 Aug 2004 08:35:19 +0000 (08:35 +0000)
committerlilo_booter <lilo_booter@d19143bc-622f-0410-bfdd-b5b2a6649095>
Tue, 31 Aug 2004 08:35:19 +0000 (08:35 +0000)
git-svn-id: https://mlt.svn.sourceforge.net/svnroot/mlt/trunk/mlt++@402 d19143bc-622f-0410-bfdd-b5b2a6649095

20 files changed:
mlt++/HOWTO [new file with mode: 0644]
mlt++/src/Makefile
mlt++/src/MltConsumer.cpp
mlt++/src/MltConsumer.h
mlt++/src/MltFilter.cpp
mlt++/src/MltFilter.h
mlt++/src/MltFrame.cpp
mlt++/src/MltFrame.h
mlt++/src/MltMultitrack.cpp
mlt++/src/MltMultitrack.h
mlt++/src/MltPlaylist.cpp
mlt++/src/MltPlaylist.h
mlt++/src/MltProducer.cpp
mlt++/src/MltProducer.h
mlt++/src/MltService.cpp
mlt++/src/MltService.h
mlt++/src/MltTractor.cpp
mlt++/src/MltTractor.h
mlt++/src/MltTransition.cpp
mlt++/src/MltTransition.h

diff --git a/mlt++/HOWTO b/mlt++/HOWTO
new file mode 100644 (file)
index 0000000..830ab29
--- /dev/null
@@ -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 <time.h>
+       #include <mlt++/Mlt.h>
+       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 <time.h>
+       #include <mlt++/Mlt.h>
+       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 <time.h>
+       #include <mlt++/Mlt.h>
+       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( );
+       }
+
+       
index bd8ae66..38d26a7 100644 (file)
@@ -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
 
index c882d4b..657c816 100644 (file)
@@ -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( ) )
 {
index eb12d68..96d3c33 100644 (file)
@@ -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( );
index 7842f55..90a178e 100644 (file)
@@ -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( ) )
 {
index b659965..ac0a720 100644 (file)
@@ -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( );
index 59af257..dc242f4 100644 (file)
@@ -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 );
+}
 
index 7cd2854..f54fd44 100644 (file)
@@ -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 );
        };
 }
 
index fbd9f24..580e79e 100644 (file)
@@ -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( ) )
 {
index 52588ee..5d43468 100644 (file)
@@ -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( );
index f81fd6e..88d19f1 100644 (file)
@@ -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( );
 }
index 904f6cd..7a6e175 100644 (file)
@@ -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( );
index a12c1da..96d9017 100644 (file)
@@ -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 )
 {
index 3c85fd9..d3b0f44 100644 (file)
@@ -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( );
index c7b11d5..3ffbb2d 100644 (file)
@@ -18,6 +18,7 @@
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+#include <string.h>
 #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, "<playlist>" ) )
+                               type = playlist_type;
+                       else if ( !strcmp( resource, "<tractor>" ) )
+                               type = tractor_type;
+                       else if ( !strcmp( resource, "<multitrack>" ) )
+                               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;
+}
index 297f954..9aef193 100644 (file)
@@ -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( );
        };
 }
 
index bb6a449..8187a28 100644 (file)
@@ -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 )
 {
index 6b78435..dc5d20f 100644 (file)
@@ -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( );
index 4ef08a5..e26feba 100644 (file)
@@ -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( ) )
 {
index 6b3c769..dbf61bd 100644 (file)
@@ -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( );