]> git.sesse.net Git - mlt/commitdiff
provisional framework docs and corrections
authorlilo_booter <lilo_booter@d19143bc-622f-0410-bfdd-b5b2a6649095>
Thu, 18 Mar 2004 12:54:29 +0000 (12:54 +0000)
committerlilo_booter <lilo_booter@d19143bc-622f-0410-bfdd-b5b2a6649095>
Thu, 18 Mar 2004 12:54:29 +0000 (12:54 +0000)
git-svn-id: https://mlt.svn.sourceforge.net/svnroot/mlt/trunk/mlt@218 d19143bc-622f-0410-bfdd-b5b2a6649095

15 files changed:
docs/framework.txt [new file with mode: 0644]
docs/westley.txt
src/framework/config.h
src/framework/mlt_factory.c
src/framework/mlt_frame.h
src/framework/mlt_producer.c
src/framework/mlt_properties.c
src/framework/mlt_properties.h
src/framework/mlt_service.c
src/framework/mlt_service.h
src/framework/mlt_types.h
src/modules/core/transition_composite.c
src/modules/sdl/consumer_sdl.c
src/tests/Makefile
src/tests/hello.c [new file with mode: 0644]

diff --git a/docs/framework.txt b/docs/framework.txt
new file mode 100644 (file)
index 0000000..e00d192
--- /dev/null
@@ -0,0 +1,1184 @@
+MLT FRAMEWORK
+-------------
+
+Preamble:
+
+       MLT is a multimedia framework designed for television broadcasting. As such, 
+       it provides a pluggable architecture for the inclusion of new audio/video 
+       sources, filters, transitions and playback devices.
+
+       The MLT framework provides the structure and utility functionality on which
+       all of the MLT applications and services are defined. 
+
+       On its own, the framework provides little more than 'abstract classes' and
+       utilities for managing resources, such as memory, properties, dynamic object
+       loading and service instantiation. 
+
+       This document is split roughly into 3 sections. The first section provides a
+       basic overview of MLT, the second section shows how it's used and the final
+       section shows shows structure and design, with an emphasis on how the system
+       is extended.
+
+
+Target Audience:
+
+       This document is provided as a 'road map' for the framework and should be
+       considered mandatory reading for anyone wishing to develop code at the MLT
+       level. 
+
+       This includes:
+
+       1. framework maintainers;
+       2. module developers;
+       3. application developers;
+       4. anyone interested in MLT.
+
+       The emphasis of the document is in explaining the public interfaces, as
+       opposed to the implementation details.
+
+       It is not required reading for the MLT client/server integration - please
+       refer to valerie.txt and dvcp.txt for more details on this area.
+
+
+SECTION 1 - BASIC OVERVIEW
+--------------------------
+
+Basic Design Information:
+
+       MLT is written in C. 
+       
+       The framework has no dependencies other than the standard C99 and POSIX 
+       libraries. 
+
+       It follows a basic Object Oriented design paradigm, and as such, much of the
+       design is loosely based on the Producer/Consumer design pattern. 
+       
+       It employs Reverse Polish Notation for the application of audio and video FX.
+
+       The framework is designed to be colour space neutral - the currently
+       implemented modules, however, are very much 8bit YUV422 oriented. In theory,
+       the modules could be entirely replaced.
+
+       A vague understanding of these terms is assumed throughout the remainder of
+       this document.
+
+
+Structure and Flow:
+
+       The general structure of an MLT 'network' is simply the connection of a
+       'producer' to a 'consumer':
+
+       +--------+   +--------+
+       |Producer|-->|Consumer|
+       +--------+   +--------+
+
+       A typical consumer requests MLT Frame objects from the producer, does 
+       something with them and when finished with a frame, closes it. 
+       
+        /\  A common confusion with the producer/consumer terminoligy used here is 
+       /!!\ that a consumer may 'produce' something. For example, the libdv consumer
+       \!!/ produces DV and the libdv producer seems to consume DV. However, the
+        \/  naming conventions refer only to producers and consumers of MLT Frames.
+
+       To put it another way - a producer produces MLT Frame objects and a consumer 
+       consumes MLT Frame objects.
+
+       An MLT Frame essentially provides an uncompressed image and its associated
+       audio samples.
+
+       Filters may also be placed between the producer and the consumer:
+
+       +--------+   +------+   +--------+
+       |Producer|-->|Filter|-->|Consumer|
+       +--------+   +------+   +--------+
+
+       A service is the collective name for producers, filters, transitions and
+       consumers. 
+
+       The communications between a connected consumer and producer or service are 
+       carried out in 3 phases:
+
+       * get the frame
+       * get the image
+       * get the audio
+
+       MLT employs 'lazy evaluation' - the image and audio need not be extracted
+       from the source until the get image and audio methods are invoked. 
+
+       In essence, the consumer pulls from what it's connected to - this means that
+       threading is typically in the domain of the consumer implementation and some
+       basic functionality is provided on the consumer class to ensure realtime
+       throughput.
+
+
+SECTION 2 - USAGE
+-----------------
+
+Hello World:
+
+       Before we go in to the specifics of the framework architecture, a working
+       example of usage is provided. 
+       
+       The following simply provides a media player:
+
+       #include <stdio.h>
+       #include <unistd.h>
+       #include <framework/mlt.h>
+
+       int main( int argc, char *argv[] )
+       {
+           // Initialise the factory
+           if ( mlt_factory_init( NULL ) == 0 )
+           {
+               // Create the default consumer
+               mlt_consumer hello = mlt_factory_consumer( NULL, NULL );
+
+               // Create via the default producer
+               mlt_producer world = mlt_factory_producer( NULL, argv[ 1 ] );
+
+               // Connect the producer to the consumer
+               mlt_consumer_connect( hello, mlt_producer_service( world ) );
+
+               // Start the consumer
+               mlt_consumer_start( hello );
+
+               // Wait for the consumer to terminate
+               while( !mlt_consumer_is_stopped( hello ) )
+                   sleep( 1 );
+
+               // Close the consumer
+               mlt_consumer_close( hello );
+
+               // Close the producer
+               mlt_producer_close( world );
+
+               // Close the factory
+               mlt_factory_close( );
+           }
+           else
+           {
+               // Report an error during initialisation
+               fprintf( stderr, "Unable to locate factory modules\n" );
+           }
+
+           // End of program
+           return 0;
+       }
+
+       This is a simple example - it doesn't provide any seeking capabilities or
+       runtime configuration options. 
+
+       The first step of any MLT application is the factory initialisation - this
+       ensures that the environment is configured and MLT can function. The factory
+       is covered in more detail below.
+
+       All services are instantiated via the factories, as shown by the
+       mlt_factory_consumer and mlt_factory_producer calls above. There are similar
+       factories for filters and transitions. There are details on all the standard
+       services in services.txt. 
+
+       The defaults requested here are a special case - the NULL usage requests
+       that we use the default producers and consumers. 
+       
+       The default producer is "fezzik". This producer matches file names to 
+       locate a service to use and attaches 'normalising filters' (such as scalers,
+       deinterlacers, resamplers and field normalisers) to the loaded content -
+       these filters ensure that the consumer gets what it asks for.
+
+       The default consumer is "sdl". The combination of fezzik and sdl will
+       provide a media player.
+
+       In this example, we connect the producer and then start the consumer. We
+       then wait until the consumer is stopped (in this case, by the action of the
+       user closing the SDL window) and finally close the consumer, producer and
+       factory before exiting the application.
+
+       Note that the consumer is threaded - waiting for an event of some sort is 
+       always required after starting and before stopping or closing the consumer.
+
+       Also note, you can override the defaults as follows:
+
+       $ MLT_CONSUMER=westley ./hello file.avi
+
+       This will create a westley xml document on stdout.
+
+       $ MLT_CONSUMER=westley MLT_PRODUCER=avformat ./hello file.avi
+
+       This will play the video using the avformat producer directly, thus it will
+       bypass the normalising functions.
+
+       $ MLT_CONSUMER=libdv ./hello file.avi > /dev/dv1394
+
+       This might, if you're lucky, do on the fly, realtime conversions of file.avi
+       to DV and broadcast it to your DV device.
+
+
+Factories:
+
+       As shown in the 'Hello World' example, factories create service objects.
+
+       The framework itself provides no services - they are provided in the form of
+       a plugin structure. A plugin is organised in the form of a 'module' and a
+       module can provide many services of different types. 
+
+       Once the factory is initialised, all the configured services are available
+       for use.
+
+       The complete set of methods associated to the factory are as follows:
+
+       int mlt_factory_init( char *prefix );
+       const char *mlt_factory_prefix( );
+       char *mlt_environment( char *name );
+       mlt_producer mlt_factory_producer( char *name, void *input );
+       mlt_filter mlt_factory_filter( char *name, void *input );
+       mlt_transition mlt_factory_transition( char *name, void *input );
+       mlt_consumer mlt_factory_consumer( char *name, void *input );
+       void mlt_factory_close( );
+
+       The mlt_factory_prefix returns the path to the location of the installed
+       modules directory. This can be specified in the mlt_factory_init call
+       itself, or it can be specified via the MLT_REPOSITORY environment variable,
+       or in the absence of either of those, it will default to the install
+       prefix/shared/mlt/modules. 
+
+       The mlt_environment provides read only access to a collection of name=value
+       pairs as shown in the following table:
+
+       +------------------+------------------------------------+------------------+
+       |Name              |Description                         |Values            |
+       +------------------+------------------------------------+------------------+
+       |MLT_NORMALISATION |The normalisation of the system     |PAL or NTSC       |
+       +------------------+------------------------------------+------------------+
+       |MLT_PRODUCER      |The default producer                |"fezzik" or other |
+       +------------------+------------------------------------+------------------+
+       |MLT_CONSUMER      |The default consumer                |"sdl" or other    |
+       +------------------+------------------------------------+------------------+
+
+       These values are initialised from the environment variables of the same
+       name.
+
+       As shown above, a producer can be created using the 'default normalising'
+       producer, and they can also be requested by name. Filters and transitions 
+       are always requested by name - there is no concept of a 'default' for these.
+
+
+Service Properties:
+
+       As shown in the services.txt document, all services have their own set of
+       properties than can be manipulated to affect their behaviour.
+
+       In order to set properties on a service, we need to retrieve the properties
+       object associated to it. For producers, this is done by invoking:
+
+           mlt_properties properties = mlt_producer_properties( producer );
+
+       All services have a similar method associated to them.
+
+       Once retrieved, setting and getting properties can be done directly on this
+       object, for example:
+
+           mlt_properties_set( properties, "name", "value" );
+       
+       A more complete description of the properties object is found below.
+
+
+Playlists:
+
+       So far, we've shown a simple producer/consumer configuration - the next
+       phase is to organise producers in playlists.
+
+       Let's assume that we're adapting the Hello World example, and wish to queue
+       a number of files for playout, ie:
+
+               hello *.avi
+
+       Instead of invoking mlt_factory_producer directly, we'll create a new
+       function called create_playlist. This function is responsible for creating
+       the playlist, creating each producer, appending to the playlist and ensuring
+       that all the producers are cleaned up when the playlist is destroyed. The
+       last point is important - a close on the playlist won't explicitly these 
+       producers. In this example, we use unique "data" properties with destructors
+       to ensure closing.
+
+       mlt_producer create_playlist( int argc, char **argv )
+       {
+           // We're creating a playlist here
+           mlt_playlist playlist = mlt_playlist_init( );
+
+           // We need the playlist properties to ensure clean up
+           mlt_properties properties = mlt_playlist_properties( playlist );
+
+           // Loop through each of the arguments
+           int i = 0;
+           for ( i = 1; i < argc; i ++ )
+           {
+               // Definie the unique key
+               char key[ 256 ];
+
+               // Create the producer
+               mlt_producer producer = mlt_factory_producer( NULL, argv[ i ] );
+
+               // Add it to the playlist
+               mlt_playlist_append( playlist, producer );
+
+               // Create a unique key for this producer
+               sprintf( key, "producer%d", i );
+
+               // Now we need to ensure the producers are destroyed
+               mlt_properties_set_data( properties, key, producer, 0, ( mlt_destructor )mlt_producer_close, NULL );
+           }
+
+           // Return the playlist as a producer
+           return mlt_playlist_producer( playlist );
+       }
+
+       Now all we need do is to replace these lines in the main function:
+
+           // Create a normalised producer
+           mlt_producer world = mlt_factory_producer( NULL, argv[ 1 ] );
+
+       with:
+
+           // Create a playlist
+           mlt_producer world = create_playlist( argc, argv );
+
+       and we have a means to play multiple clips.
+
+
+Filters:
+
+       Inserting filters between the producer and consumer is just a case of
+       instantiating the filters, connecting the first to the producer, the next
+       to the previous filter and the last filter to the consumer.
+
+       For example:
+
+           // Create a producer from something
+           mlt_producer producer = mlt_factory_producer( ... );
+
+           // Create a consumer from something
+           mlt_consumer consumer = mlt_factory_consumer( ... );
+
+           // Create a greyscale filter
+           mlt_filter filter = mlt_factory_filter( "greyscale", NULL );
+
+           // Connect the filter to the producer
+           mlt_filter_connect( filter, mlt_producer_service( producer ), 0 );
+
+           // Connect the consumer to filter
+           mlt_consumer_connect( consumer, mlt_filter_service( filter ) );
+
+       As with producers and consumers, filters can be manipulated via their
+       properties object - the mlt_filter_properties method can be invoked and
+       properties can be set as needed.
+
+       The additional argument in the filter connection is an important one as it
+       dicates the 'track' on which the filter operates. For basic producers and
+       playlists, there's only one track (0), and as you will see in the next
+       section, even multiple tracks have a single track output.
+
+
+Multiple Tracks and Transitions:
+
+       MLT's approach to mutliple tracks is governed by two requirements:
+
+       1) The need for a consumer and producer to communicate with one another via
+       a single frame;
+       2) The desire to be able to serialise and manipulate a 'network' (or filter
+       graph if you prefer).
+
+       We can visualise a multitrack in the way that an NLE presents it:
+
+          +-----------------+                          +-----------------------+
+       0: |a1               |                          |a2                     |
+          +---------------+-+--------------------------+-+---------------------+
+       1:                 |b1                            |
+                          +------------------------------+
+
+       The overlapping areas of track 0 and 1 would (presumably) have some kind of
+       transition - without a transition, the frames from a1 and a2 would be shown 
+       during the areas of overlap.
+
+       MLT has a multitrack object, but it is not a producer in the sense that it
+       can be connected directly to a consumer and everything will work correctly.
+       A consumer would treat it precisely as it would a normal producer, and, in
+       the case of the multitrack above, you would never see anything from track 1
+       other than the transitions between the clips - the gap between a1 and a2 
+       would show test frames.
+
+       This happens because a consumer pulls one frame from the producer it's 
+       connected to while a multitrack will provide one frame per track.
+       Something, somewhere, must ensure that all frames are pulled from the
+       multitrack and elect the correct frame to pass on.
+
+       Hence, MLT provides a wrapper for the multitrack, which is called a
+       'tractor', and its the tractors task to ensure that all tracks are pulled
+       evenly, the correct frame is output and that we have 'producer like'
+       behaviour.
+
+       Thus, a mulitrack is conceptually 'pulled' by a tractor as shown here:
+
+       +----------+
+       |multitrack|
+       | +------+ |    +-------+
+       | |track0|-|--->|tractor|
+       | +------+ |    |\      |
+       |          |    | \     |
+       | +------+ |    |  \    |
+       | |track1|-|--->|---o---|--->
+       | +------+ |    |  /    |
+       |          |    | /     |
+       | +------+ |    |/      |
+       | |track2|-|--->|       |
+       | +------+ |    +-------+
+       +----------+
+
+       With a combination of the two, we can now connect multitracks to consumers.
+       The first non-test card will be retrieved and passed on. 
+
+       The tracks can be producers, playlists, or even other tractors. 
+
+       Now we wish to insert filters and transitions between the mulitrack and the
+       tractor. We can do this directly by inserting filters directly between the
+       tractor and the multitrack, but this involves a lot of connecting and
+       reconnecting left and right producers and consumers, and it seemed only fair
+       that we should be able to automate that process. 
+       
+       So in keeping with our agricultural theme, the concept of the 'field' was 
+       born. We 'plant' filters and transitions in the field and the tractor pulls 
+       the multitrack (think of a combine harvester :-)) over the field and 
+       produces a 'bail' (sorry - kidding - frame :-)).
+
+       Conceptually, we can see it like this:
+
+       +----------+
+       |multitrack|
+       | +------+ |    +-------------+    +-------+
+       | |track0|-|--->|field        |--->|tractor|
+       | +------+ |    |             |    |\      |
+       |          |    |   filters   |    | \     |
+       | +------+ |    |     and     |    |  \    |
+       | |track1|-|--->| transitions |--->|---o---|--->
+       | +------+ |    |             |    |  /    |
+       |          |    |             |    | /     |
+       | +------+ |    |             |    |/      |
+       | |track2|-|--->|             |--->|       |
+       | +------+ |    +-------------+    +-------+
+       +----------+
+
+       In reality, we create a field first, and from that we obtain a multitrack
+       and a tractor. We can then populate the multitrack, field and finally,
+       connect the tractor to the consumer. 
+       
+       The reasoning behind this is possibly flawed - it might have made more 
+       sense to produce the tractor and have it encapsulate the field and the
+       multitrack as that is how it looks to a connected consumer:
+
+       +-----------------------------------------------+
+       |tractor          +--------------------------+  |
+       | +----------+    | +-+    +-+    +-+    +-+ |  |
+       | |multitrack|    | |f|    |f|    |t|    |t| |  |
+       | | +------+ |    | |i|    |i|    |r|    |r| |  |
+       | | |track0|-|--->| |l|- ->|l|- ->|a|--->|a|\|  |
+       | | +------+ |    | |t|    |t|    |n|    |n| |  |
+       | |          |    | |e|    |e|    |s|    |s| |\ |
+       | | +------+ |    | |r|    |r|    |i|    |i| | \|
+       | | |track1|-|- ->| |0|--->|1|--->|t|--->|t|-|--o--->
+       | | +------+ |    | | |    | |    |i|    |i| | /|
+       | |          |    | | |    | |    |o|    |o| |/ |
+       | | +------+ |    | | |    | |    |n|    |n| |  |
+       | | |track2|-|- ->| | |- ->| |--->|0|- ->|1|/|  |
+       | | +------+ |    | | |    | |    | |    | | |  |
+       | +----------+    | +-+    +-+    +-+    +-+ |  |
+       |                 +--------------------------+  |
+       +-----------------------------------------------+
+
+       An example will hopefully clarify this. 
+       
+       Let's assume that we want to provide a 'watermark' to our hello world 
+       example. We have already extended the example to play multiple clips,
+       and now we will place a text based watermark, reading 'Hello World' in 
+       the top left hand corner:
+
+       mlt_producer create_tracks( int argc, char **argv )
+       {
+           // Create the field
+           mlt_field field = mlt_field_init( );
+       
+           // Obtain the multitrack
+           mlt_multitrack multitrack = mlt_field_multitrack( field );
+       
+           // Obtain the tractor
+           mlt_tractor tractor = mlt_field_tractor( field );
+       
+           // Obtain a composite transition
+           mlt_transition transition = mlt_factory_transition( "composite", "10%,10%:15%x15%" );
+       
+           // Create track 0
+           mlt_producer track0 = create_playlist( argc, argv );
+       
+           // Create the watermark track - note we NEED fezzik for scaling here
+           mlt_producer track1 = mlt_factory_producer( "fezzik", "pango" );
+       
+           // Get the length of track0
+           mlt_position length = mlt_producer_get_playtime( track0 );
+       
+           // Set the properties of track1
+           mlt_properties properties = mlt_producer_properties( track1 );
+           mlt_properties_set( properties, "text", "Hello\nWorld" );
+           mlt_properties_set_position( properties, "in", 0 );
+           mlt_properties_set_position( properties, "out", length - 1 );
+           mlt_properties_set_position( properties, "length", length );
+       
+           // Now set the properties on the transition
+           properties = mlt_transition_properties( transition );
+           mlt_properties_set_position( properties, "in", 0 );
+           mlt_properties_set_position( properties, "out", length - 1 );
+       
+           // Add our tracks to the multitrack
+           mlt_multitrack_connect( multitrack, track0, 0 );
+           mlt_multitrack_connect( multitrack, track1, 1 );
+       
+           // Now plant the transition
+           mlt_field_plant_transition( field, transition, 0, 1 );
+       
+           // Now set the properties on the tractor
+           properties = mlt_tractor_properties( tractor );
+           mlt_properties_set_data( properties, "multitrack", multitrack, 0, ( mlt_destructor )mlt_multitrack_close, NULL );
+           mlt_properties_set_data( properties, "field", field, 0, ( mlt_destructor )mlt_field_close, NULL );
+           mlt_properties_set_data( properties, "track0", track0, 0, ( mlt_destructor )mlt_producer_close, NULL );
+           mlt_properties_set_data( properties, "track1", track1, 0, ( mlt_destructor )mlt_producer_close, NULL );
+           mlt_properties_set_data( properties, "transition", transition, 0, ( mlt_destructor )mlt_transition_close, NULL );
+       
+           // Return the tractor
+           return mlt_tractor_producer( tractor );
+       }
+
+       Now all we need do is to replace these lines in the main function:
+
+           // Create a playlist
+           mlt_producer world = create_playlist( argc, argv );
+
+       with:
+
+           // Create a watermarked playlist
+           mlt_producer world = create_tracks( argc, argv );
+
+       and we have a means to play multiple clips with a horribly obtrusive
+       watermark - just what the world needed, right? ;-)
+
+
+SECTION 3 - STRUCTURE AND DESIGN
+--------------------------------
+
+Class Heirachy:
+
+       The mlt framework consists of an OO class heirachy which consists of the
+       following public classes and abstractions:
+
+       mlt_properties
+         mlt_frame
+         mlt_service
+           mlt_producer
+             mlt_playlist
+             mlt_tractor
+           mlt_filter
+           mlt_transition
+           mlt_consumer
+       mlt_deque
+       mlt_pool
+       mlt_factory
+
+       Each class defined above can be read as extending the classes above and to
+       the left.
+
+       The following sections describe the properties, stacking/queuing and memory 
+       pooling functionality provided by the framework - these are key components 
+       and a basic understanding of these is required for the remainder of the
+       documentation.
+
+
+mlt_properties:
+
+       The properties class is the base class for the frame and service classes.
+
+       It is designed to provide an efficient lookup table for various types of
+       information, such as strings, integers, floating points values and pointers
+       to data and data structures. 
+
+       All properties are indexed by a unique string. 
+       
+       The most basic use of properties is as follows:
+
+           // 1. Create a new, empty properties set;
+           mlt_properties properties = mlt_properties_new( );
+
+           // 2. Assign the value "world" to the property "hello";
+           mlt_properties_set( properties, "hello", "world" );
+
+           // 3. Retrieve and print the value of "hello";
+           printf( "%s\n", mlt_properties_get( properties, "hello" ) );
+
+           // 4. Reassign "hello" to "world!";
+           mlt_properties_set( properties, "hello", "world!" );
+
+           // 5. Retrieve and print the value of "hello";
+           printf( "%s\n", mlt_properties_get( properties, "hello" ) );
+
+           // 6. Assign the value "0" to "int";
+           mlt_properties_set( properties, "int", "0" );
+
+           // 7. Retrieve and print the integer value of "int";
+           printf( "%d\n", mlt_properties_get_int( properties, "int" ) );
+
+           // 8. Assign the integer value 50 to "int2";
+           mlt_properties_set_int( properties, "int2", 50 );
+
+           // 9. Retrieve and print the double value of "int2";
+           printf( "%s\n", mlt_properties_get( properties, "int2" ) );
+
+       Steps 2 through 5 demonstrate that the "name" is unique - set operations on 
+       an existing "name" change the value. They also free up memory associated to 
+       the previous value. Note that it also possible to change type in this way
+       too.
+
+       Steps 6 and 7 demonstrate that the properties object handles deserialisation
+       from strings. The string value of "50" is set, the integer value of 50 is
+       retrieved.
+
+       Steps 8 and 9 demonstrate that the properties object handles serialisation
+       to strings.
+
+       To show all the name/value pairs in a properties, it is possible to iterate
+       through them:
+
+           int i = 0;
+           for ( i = 0; i < mlt_properties_count( properties ); i ++ )
+               printf( "%s = %s\n", mlt_properties_get_name( properties, i ),
+                                    mlt_properties_get_value( properties, i ) );
+
+       Note that properties are retrieved in the order in which they are set. 
+
+       Properties are also used to hold pointers to memory. This is done via the
+       set_data call:
+
+       uint8_t *image = malloc( size );
+       mlt_properties_set_data( properties, "image", image, size, NULL, NULL );
+
+       In this example, we specify that the pointer can be retrieved from
+       properties by a subsequent request to get_data:
+
+           image = mlt_properties_get_data( properties, "image", &size );
+
+       or:
+
+           image = mlt_properties_get_data( properties, "image", NULL );
+
+       if we don't wish to retrieve the size.
+
+       Two points here:
+
+       1) The allocated memory remains after the properties object is closed unless
+          you specify a destructor. In the case above, this can be done with:
+
+          mlt_properties_set_data( properties, "image", image, size, free, NULL );
+
+          When the properties are closed, or the value of "image" is changed, the 
+          destructor is invoked.
+       
+       2) The string value returned by mlt_properties_get is NULL. Typically, you
+          wouldn't wish to serialise an image as a string, but other structures
+          might need such functionality - you can specify a serialiser as the last
+          argument if required (declaration is char *serialise( void * )).
+
+       Properties also provides some more advanced usage capabilities. 
+       
+       It has the ability to inherit all serialisable values from another properties 
+       object:
+
+           mlt_properties_inherit( this, that );
+
+       It has the ability to mirror properties set on this on another set of
+       properties:
+
+           mlt_properties_mirror( this, that );
+
+       After this call, all serialisable values set on this are passed on to that.
+
+
+mlt_deque:
+
+       Stacks and queues are essential components in the MLT framework. Being of a
+       lazy disposition, we elected to implement a 'Double Ended Queue' (deque) -
+       this encapsulates the functionality of both.
+
+       The API of the deque is defined as follows:
+
+       mlt_deque mlt_deque_init( );
+       int mlt_deque_count( mlt_deque this );
+       int mlt_deque_push_back( mlt_deque this, void *item );
+       void *mlt_deque_pop_back( mlt_deque this );
+       int mlt_deque_push_front( mlt_deque this, void *item );
+       void *mlt_deque_pop_front( mlt_deque this );
+       void *mlt_deque_peek_back( mlt_deque this );
+       void *mlt_deque_peek_front( mlt_deque this );
+       void mlt_deque_close( mlt_deque this );
+
+       The stacking operations are used in a number of places:
+
+       * Reverse Polish Notation (RPN) image and audio operations
+       * memory pooling
+
+       The queuing operations are used in typical frame based consumers to allow
+       buffering.
+
+
+mlt_pool:
+
+       The MLT framework provides memory pooling capabilities through the mlt_pool
+       API. Once initilialised, these can be seen as a straightforward drop in
+       replacement for malloc/realloc/free functionality.
+
+       The background behind this API is that malloc/free operations are
+       notoriously inefficient, especially when dealing with large blocks of memory
+       (such as an image). On linux, malloc is optimised for memory allocations
+       less than 128k - memory blocks allocated of these sizes or less are retained
+       in the process heap for subsequent reuse, thus bypassing the kernel calls
+       for repeated allocation/frees for small blocks of memory. However, blocks of
+       memory larger than that require kernel calls and this has a detrimental
+       impact on performance.
+
+       The mlt_pool design is simply to hold a list of stacks - there is one stack
+       per 2^n bytes (where n is between 8 and 31). When an alloc is called, the
+       requested size is rounded to the next 2^n, the stack is retrieved for that
+       size, and an item is popped or created if the stack is empty. 
+
+       Each item has a 'header', situated immediately before the returned address - 
+       this holds the 'stack' to which the item belongs.
+
+       When an item is released, we retrieve the header, obtain the stack and push
+       it back.
+
+       Thus, from the programmers point of view, the API is the same as the
+       traditional malloc/realloc/free calls:
+
+       void *mlt_pool_alloc( int size );
+       void *mlt_pool_realloc( void *ptr, int size );
+       void mlt_pool_release( void *release );
+
+
+mlt_frame:
+
+       A frame object is essentially defined as:
+
+       +------------+
+       |frame       |
+       +------------+
+       | properties |
+       | image stack|
+       | audio stack|
+       +------------+
+
+       The life cycle of a frame can be represented as follows:
+
+       +-----+----------------------+-----------------------+---------------------+
+       |Stage|Producer              |Filter                 |Consumer             |
+       +-----+----------------------+-----------------------+---------------------+
+       | 0.0 |                      |                       |Request frame        |
+       +-----+----------------------+-----------------------+---------------------+
+       | 0.1 |                      |Receives request       |                     |
+       |     |                      |Request frame          |                     |
+       +-----+----------------------+-----------------------+---------------------+
+       | 0.2 |Receives request      |                       |                     |
+       |     |Generates frame for   |                       |                     |
+       |     |current position      |                       |                     |
+       |     |Increments position   |                       |                     |
+       +-----+----------------------+-----------------------+---------------------+
+       | 0.3 |                      |Receives frame         |                     |
+       |     |                      |Updates frame          |                     |
+       +-----+----------------------+-----------------------+---------------------+
+       | 0.4 |                      |                       |Receives frame       |
+       +-----+----------------------+-----------------------+---------------------+
+
+       Note that neither the filter nor the consumer have any conception of
+       'position' until they receive a frame. Speed and position are properties of
+       the producer, and they are assigned to the frame object when the producer
+       creates it.
+
+       Step 0.3 is a critical one here - if the filter determines that the frame is
+       of interest to it, then it should manipulate the image and/or audio stacks
+       and properties as required.
+
+       Assuming that the filter deals with both image and audio, then it should
+       push data and methods on to the stacks which will deal with the processing. 
+       This can be done with the mlt_frame_push_image and audio methods. In order for 
+       the filter to register interest in the frame, the stacks should hold:
+
+       image stack:
+       [ producer_get_image ] [ data1 ] [ data2 ] [ filter_get_image ]
+
+       audio stack:
+       [ producer_get_audio ] [ data ] [ filter_get_audio ]
+
+       The filter_get methods are invoked automatically when the consumer invokes a
+       get_image on the frame. 
+
+       +-----+----------------------+-----------------------+---------------------+
+       |Stage|Producer              |Filter                 |Consumer             |
+       +-----+----------------------+-----------------------+---------------------+
+       | 1.0 |                      |                       |frame_get_image      |
+       +-----+----------------------+-----------------------+---------------------+
+       | 1.1 |                      |filter_get_image:      |                     |
+       |     |                      | pop data2 and data1   |                     |
+       |     |                      | frame_get_image       |                     |
+       +-----+----------------------+-----------------------+---------------------+
+       | 1.2 |producer_get_image    |                       |                     |
+       |     |  Generates image     |                       |                     |
+       +-----+----------------------+-----------------------+---------------------+
+       | 1.3 |                      |Receives image         |                     |
+       |     |                      |Updates image          |                     |
+       +-----+----------------------+-----------------------+---------------------+
+       | 1.4 |                      |                       |Receives image       |
+       +-----+----------------------+-----------------------+---------------------+
+
+       Obviously, if the filter isn't interested in the image, then it should leave
+       the stack alone, and then the consumer will retrieve its image directly from
+       the producer.
+
+       Similarly, audio is handled as follows:
+
+       +-----+----------------------+-----------------------+---------------------+
+       |Stage|Producer              |Filter                 |Consumer             |
+       +-----+----------------------+-----------------------+---------------------+
+       | 2.0 |                      |                       |frame_get_audio      |
+       +-----+----------------------+-----------------------+---------------------+
+       | 2.1 |                      |filter_get_audio:      |                     |
+       |     |                      | pop data              |                     |
+       |     |                      | frame_get_audio       |                     |
+       +-----+----------------------+-----------------------+---------------------+
+       | 2.2 |producer_get_audio    |                       |                     |
+       |     |  Generates audio     |                       |                     |
+       +-----+----------------------+-----------------------+---------------------+
+       | 2.3 |                      |Receives audio         |                     |
+       |     |                      |Updates audio          |                     |
+       +-----+----------------------+-----------------------+---------------------+
+       | 2.4 |                      |                       |Receives audio       |
+       +-----+----------------------+-----------------------+---------------------+
+
+       And finally, when the consumer is done with the frame, it should close it.
+
+       Note that a consumer may not evaluate both image and audio for any given
+       frame, especially in a realtime environment. See 'Realtime Considerations'
+       below.
+
+       By default, a frame has the following properties:
+
+       +------------------+------------------------------------+------------------+
+       |Name              |Description                         |Values            |
+       +------------------+------------------------------------+------------------+
+       |_position         |The producers frame position        |0 to n            |
+       +------------------+------------------------------------+------------------+
+       |_speed            |The producers speed                 |double            |
+       +------------------+------------------------------------+------------------+
+       |image             |The generated image                 |NULL or pointer   |
+       +------------------+------------------------------------+------------------+
+       |alpha             |The generated alpha mask            |NULL or pointer   |
+       +------------------+------------------------------------+------------------+
+       |width             |The width of the image              |                  |
+       +------------------+------------------------------------+------------------+
+       |height            |The height of the image             |                  |
+       +------------------+------------------------------------+------------------+
+       |normalised_width  |The normalised width of the image   |720               |
+       +------------------+------------------------------------+------------------+
+       |normalised_height |The normalised height of the image  |576 or 480        |
+       +------------------+------------------------------------+------------------+
+       |progressive       |Indicates progressive/interlaced    |0 or 1            |
+       +------------------+------------------------------------+------------------+
+       |top_field_first   |Indicates top field first           |0 or 1            |
+       +------------------+------------------------------------+------------------+
+       |audio             |The generated audio                 |NULL or pointer   |
+       +------------------+------------------------------------+------------------+
+       |frequency         |The frequency of the audio          |                  |
+       +------------------+------------------------------------+------------------+
+       |channels          |The channels of the audio           |                  |
+       +------------------+------------------------------------+------------------+
+       |samples           |The samples of the audio            |                  |
+       +------------------+------------------------------------+------------------+
+       |aspect_ratio      |The aspect ratio of the image       |double            |
+       +------------------+------------------------------------+------------------+
+       |test_image        |Used to indicate no image available |0 or 1            |
+       +------------------+------------------------------------+------------------+
+       |test_audio        |Used to indicate no audio available |0 or 1            |
+       +------------------+------------------------------------+------------------+
+
+       The consumer can attach the following properties which affect the default
+       behaviour of a frame:
+
+       +------------------+------------------------------------+------------------+
+       |test_card_producer|Synthesise test images from here    |NULL or pointer   |
+       +------------------+------------------------------------+------------------+
+       |consumer_aspect_  |Apply this aspect ratio to the test |double            |
+       |ratio             |card producer                       |                  |
+       +------------------+------------------------------------+------------------+
+       |rescale.interp    |Use this scale method for test image|"string"          |
+       +------------------+------------------------------------+------------------+
+
+       While most of these are mainly self explainatory, the normalised_width and
+       normalised_height values require a little explaination. These are required
+       to ensure that effects are consistently handled as PAL or NTSC, regardless 
+       of the consumers or producers width/height image request. 
+
+       The test_image and audio flags are used to determine when images and audio
+       should be synthesised.
+
+       Additional properties may be provided by the producer implementation, and
+       filters, transitions and consumers may add additional properties to
+       communicate specific requests. These are documented in modules.txt.
+
+       The complete API for the mlt frame is as follows:
+
+       mlt_frame mlt_frame_init( );
+       mlt_properties mlt_frame_properties( mlt_frame this );
+       int mlt_frame_is_test_card( mlt_frame this );
+       int mlt_frame_is_test_audio( mlt_frame this );
+       double mlt_frame_get_aspect_ratio( mlt_frame this );
+       int mlt_frame_set_aspect_ratio( mlt_frame this, double value );
+       mlt_position mlt_frame_get_position( mlt_frame this );
+       int mlt_frame_set_position( mlt_frame this, mlt_position value );
+       int mlt_frame_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable );
+       uint8_t *mlt_frame_get_alpha_mask( mlt_frame this );
+       int mlt_frame_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples );
+       int mlt_frame_push_get_image( mlt_frame this, mlt_get_image get_image );
+       mlt_get_image mlt_frame_pop_get_image( mlt_frame this );
+       int mlt_frame_push_frame( mlt_frame this, mlt_frame that );
+       mlt_frame mlt_frame_pop_frame( mlt_frame this );
+       int mlt_frame_push_service( mlt_frame this, void *that );
+       void *mlt_frame_pop_service( mlt_frame this );
+       int mlt_frame_push_audio( mlt_frame this, void *that );
+       void *mlt_frame_pop_audio( mlt_frame this );
+       void mlt_frame_close( mlt_frame this );
+
+mlt_service:
+
+       The service base class extends properties and allows 0 to m inputs and 0 to
+       n outputs and is represented as follows:
+
+           +-----------+
+       - ->|           |- ->
+       - ->|  Service  |- ->
+       - ->|           |
+           +-----------+
+           | properties|
+           +-----------+
+
+       Descendents of service impose restrictions on how inputs and outputs can be 
+       connected and will provide a basic set of properties. Typically, the service 
+       instance is encapsulated by the descendent in order for it to ensure that
+       its connection rules are followed.
+
+       A service does not define any properties when constructed. It should be
+       noted that producers, filters and transitions my be serialised (say, via the
+       westley consumer), and care should be taken to distinguish between
+       serialisable and transient properties. The convention used is to prefix
+       transient properties with an underscore.
+
+       The public interface is defined by the following functions:
+
+       int mlt_service_init( mlt_service this, void *child );
+       mlt_properties mlt_service_properties( mlt_service this );
+       int mlt_service_connect_producer( mlt_service this, mlt_service producer, int index );
+       int mlt_service_get_frame( mlt_service this, mlt_frame_ptr frame, int index );
+       void mlt_service_close( mlt_service this );
+
+       Typically, only direct descendents of services need invoke these methods and
+       developers are encouraged to use those extensions when definining new
+       services.
+
+
+mlt_producer:
+
+       A producer has 0 inputs and 1 output:
+
+           +-----------+
+           |           |
+           | Producer  |--->
+           |           |
+           +-----------+
+           | service   |
+           +-----------+
+
+       A producer provides an abstraction for file readers, pipes, streams or any
+       other image or audio input. 
+
+       When instantiated, a producer has the following properties:
+
+       +------------------+------------------------------------+------------------+
+       |Name              |Description                         |Values            |
+       +------------------+------------------------------------+------------------+
+       |mlt_type          |The producers type                  |mlt_producer      |
+       +------------------+------------------------------------+------------------+
+       |_position         |The producers frame position        |0 to n            |
+       +------------------+------------------------------------+------------------+
+       |_speed            |The producers speed                 |double            |
+       +------------------+------------------------------------+------------------+
+       |fps               |The output frames per second        |25 or 29.97       |
+       +------------------+------------------------------------+------------------+
+       |in                |The in point in frames              |0 to length - 1   |
+       +------------------+------------------------------------+------------------+
+       |out               |The out point in frames             |in to length - 1  |
+       +------------------+------------------------------------+------------------+
+       |length            |The length of the input in frames   |0 to n            |
+       +------------------+------------------------------------+------------------+
+       |aspect_ratio      |aspect_ratio of the source          |0 to n            |
+       +------------------+------------------------------------+------------------+
+       |eof               |end of clip behaviour               |"pause" or "loop" |
+       +------------------+------------------------------------+------------------+
+       |resource          |Constructor argument (ie: file name)|"<resource>"      |
+       +------------------+------------------------------------+------------------+
+
+       Additional properties may be provided by the producer implementation.
+
+       The public interface is defined by the following functions:
+
+       int mlt_producer_init( mlt_producer this, void *child );
+       mlt_service mlt_producer_service( mlt_producer this );
+       mlt_properties mlt_producer_properties( mlt_producer this );
+       int mlt_producer_seek( mlt_producer this, mlt_position position );
+       mlt_position mlt_producer_position( mlt_producer this );
+       mlt_position mlt_producer_frame( mlt_producer this );
+       int mlt_producer_set_speed( mlt_producer this, double speed );
+       double mlt_producer_get_speed( mlt_producer this );
+       double mlt_producer_get_fps( mlt_producer this );
+       int mlt_producer_set_in_and_out( mlt_producer this, mlt_position in, mlt_position out );
+       mlt_position mlt_producer_get_in( mlt_producer this );
+       mlt_position mlt_producer_get_out( mlt_producer this );
+       mlt_position mlt_producer_get_playtime( mlt_producer this );
+       mlt_position mlt_producer_get_length( mlt_producer this );
+       void mlt_producer_prepare_next( mlt_producer this );
+       void mlt_producer_close( mlt_producer this );
+
+       For the sake of discussion here, we'll assume that someone wants to provide
+       a new producer which simply generates green frames and silent audio :-) -
+       we'll call the producer 'green'.
+
+       // Forward reference
+       static int producer_get_frame( mlt_service service, mlt_frame_ptr frame, int index );
+
+       mlt_producer producer_green( void *arg )
+       {
+               // Create a new producer
+               mlt_producer this = mlt_producer_new( );
+
+               // Check that we were allocated a new producer
+               if ( this != NULL )
+               {
+                       // Get the service 
+                       mlt_service service = mlt_producer_service( this );
+
+                       // We need to override the get_frame method
+                       service->get_frame = producer_get_frame;
+               }
+
+               // Return this producer
+               return this;
+       }
+
+       static int producer_get_frame( mlt_service service, mlt_frame_ptr frame, int index )
+       {
+               // Create a new frame
+               *frame = mlt_frame_init( );
+
+               // Specify the get_image
+               mlt_frame_push_get_image( *frame, producer_get_image );
+
+               // Specify the get_audio
+               mlt_frame_push_audio( *frame, producer_get_audio );
+
+               // Return that all was successful
+               return 0;
+       }
+
+mlt_filter:
+
+       The public interface is defined by the following functions:
+
+       int mlt_filter_init( mlt_filter this, void *child );
+       mlt_filter mlt_filter_new( );
+       mlt_service mlt_filter_service( mlt_filter this );
+       mlt_properties mlt_filter_properties( mlt_filter this );
+       mlt_frame mlt_filter_process( mlt_filter this, mlt_frame that );
+       int mlt_filter_connect( mlt_filter this, mlt_service producer, int index );
+       void mlt_filter_set_in_and_out( mlt_filter this, mlt_position in, mlt_position out );
+       int mlt_filter_get_track( mlt_filter this );
+       mlt_position mlt_filter_get_in( mlt_filter this );
+       mlt_position mlt_filter_get_out( mlt_filter this );
+       void mlt_filter_close( mlt_filter );
+
+
+mlt_transition:
+
+       The public interface is defined by the following functions:
+
+       int mlt_transition_init( mlt_transition this, void *child );
+       mlt_transition mlt_transition_new( );
+       mlt_service mlt_transition_service( mlt_transition this );
+       mlt_properties mlt_transition_properties( mlt_transition this );
+       int mlt_transition_connect( mlt_transition this, mlt_service producer, int a_track, int b_track );
+       void mlt_transition_set_in_and_out( mlt_transition this, mlt_position in, mlt_position out );
+       int mlt_transition_get_a_track( mlt_transition this );
+       int mlt_transition_get_b_track( mlt_transition this );
+       mlt_position mlt_transition_get_in( mlt_transition this );
+       mlt_position mlt_transition_get_out( mlt_transition this );
+       mlt_frame mlt_transition_process( mlt_transition this, mlt_frame a_frame, mlt_frame b_frame );
+       void mlt_transition_close( mlt_transition this );
+
+
+mlt_consumer:
+
+       The public interface is defined by the following functions:
+
+       int mlt_consumer_init( mlt_consumer this, void *child );
+       mlt_service mlt_consumer_service( mlt_consumer this );
+       mlt_properties mlt_consumer_properties( mlt_consumer this );
+       int mlt_consumer_connect( mlt_consumer this, mlt_service producer );
+       int mlt_consumer_start( mlt_consumer this );
+       mlt_frame mlt_consumer_get_frame( mlt_consumer this );
+       mlt_frame mlt_consumer_rt_frame( mlt_consumer this );
+       int mlt_consumer_stop( mlt_consumer this );
+       int mlt_consumer_is_stopped( mlt_consumer this );
+       void mlt_consumer_close( mlt_consumer );
+
+
+Specialised Producers:
+
+       There are two major types of specialised producers - playlists and tractors.
+
+       The following sections describe these.
+
+
+mlt_playlist:
+
+       mlt_playlist mlt_playlist_init( );
+       mlt_producer mlt_playlist_producer( mlt_playlist this );
+       mlt_service mlt_playlist_service( mlt_playlist this );
+       mlt_properties mlt_playlist_properties( mlt_playlist this );
+       int mlt_playlist_count( mlt_playlist this );
+       int mlt_playlist_clear( mlt_playlist this );
+       int mlt_playlist_append( mlt_playlist this, mlt_producer producer );
+       int mlt_playlist_append_io( mlt_playlist this, mlt_producer producer, mlt_position in, mlt_position out );
+       int mlt_playlist_blank( mlt_playlist this, mlt_position length );
+       mlt_position mlt_playlist_clip( mlt_playlist this, mlt_whence whence, int index );
+       int mlt_playlist_current_clip( mlt_playlist this );
+       mlt_producer mlt_playlist_current( mlt_playlist this );
+       int mlt_playlist_get_clip_info( mlt_playlist this, mlt_playlist_clip_info *info, int index );
+       int mlt_playlist_insert( mlt_playlist this, mlt_producer producer, int where, mlt_position in, mlt_position out );
+       int mlt_playlist_remove( mlt_playlist this, int where );
+       int mlt_playlist_move( mlt_playlist this, int from, int to );
+       int mlt_playlist_resize_clip( mlt_playlist this, int clip, mlt_position in, mlt_position out );
+       void mlt_playlist_close( mlt_playlist this );
+
+mlt_tractor:
+
+
+mlt_factory
+
index 3984083f0a8bd865585d984e37d10d1770eb6640..89e59288d82cc7768e8a3bf5cf84105d08ee03b0 100644 (file)
@@ -125,7 +125,6 @@ Playlists:
 
 Interlude - Introducing Multitracks:
 
-       
        So far we've defined basic producers and playlists/tracks - the tractor is
        the element that allows us to arrange our tracks and specify filters and
        transitions. Similarly to a playlist, a tractor is a container.
index fec9861dca4e68106ca6e2e942880f74cdbd473d..7f5019f663505ee3c6e020d14f81865334dcf2ca 100644 (file)
@@ -4,7 +4,7 @@
 #define _MLT_CONFIG_H_
 
 #define PREFIX                 "/usr/local"
-#define PREFIX_DATA            PREFIX "/share"
+#define PREFIX_DATA            PREFIX "/share/mlt/modules"
 
 #endif
 
index 0b4df21481c375f3b9a0bc640f339efaf3745362..dee338e3bab2d36d0716568c8db2791c48454de4 100644 (file)
@@ -46,6 +46,10 @@ int mlt_factory_init( char *prefix )
        // Only initialise once
        if ( mlt_prefix == NULL )
        {
+               // Allow user over rides
+               if ( prefix == NULL )
+                       prefix = getenv( "MLT_REPOSITORY" );
+
                // If no directory is specified, default to install directory
                if ( prefix == NULL )
                        prefix = PREFIX_DATA;
@@ -58,7 +62,9 @@ int mlt_factory_init( char *prefix )
 
                // Create the global properties
                global_properties = mlt_properties_new( );
-               mlt_properties_set( global_properties, "MLT_NORMALISATION", getenv( "MLT_NORMALISATION" ) );
+               mlt_properties_set_or_default( global_properties, "MLT_NORMALISATION", getenv( "MLT_NORMALISATION" ), "PAL" );
+               mlt_properties_set_or_default( global_properties, "MLT_PRODUCER", getenv( "MLT_PRODUCER" ), "fezzik" );
+               mlt_properties_set_or_default( global_properties, "MLT_CONSUMER", getenv( "MLT_CONSUMER" ), "sdl" );
 
                // Create the object list.
                object_list = mlt_properties_new( );
@@ -94,7 +100,15 @@ char *mlt_environment( char *name )
 
 mlt_producer mlt_factory_producer( char *service, void *input )
 {
-       mlt_producer obj = mlt_repository_fetch( producers, service, input );
+       mlt_producer obj = NULL;
+
+       // Pick up the default normalising producer if necessary
+       if ( service == NULL )
+               service = mlt_environment( "MLT_PRODUCER" );
+
+       // Try to instantiate via the specified service
+       obj = mlt_repository_fetch( producers, service, input );
+
        if ( obj != NULL )
        {
                mlt_properties properties = mlt_producer_properties( obj );
@@ -143,7 +157,13 @@ mlt_transition mlt_factory_transition( char *service, void *input )
 
 mlt_consumer mlt_factory_consumer( char *service, void *input )
 {
-       mlt_consumer obj = mlt_repository_fetch( consumers, service, input );
+       mlt_consumer obj = NULL;
+
+       if ( service == NULL )
+               service = mlt_environment( "MLT_CONSUMER" );
+
+       obj = mlt_repository_fetch( consumers, service, input );
+
        if ( obj != NULL )
        {
                mlt_properties properties = mlt_consumer_properties( obj );
index f1cd0fede442dc05b49269d2568cf2c1d3b0d1ef..e288c1b5ac39296606dc08ed219510ddc3d91a35 100644 (file)
 #include "mlt_properties.h"
 #include "mlt_deque.h"
 
-typedef enum
-{
-       mlt_video_standard_pal = 0,
-       mlt_video_standard_ntsc
-}
-mlt_video_standard;
-
-typedef enum
-{
-       mlt_audio_none = 0,
-       mlt_audio_pcm
-}
-mlt_audio_format;
-
 typedef int ( *mlt_get_image )( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable );
 
 struct mlt_frame_s
@@ -62,21 +48,17 @@ extern double mlt_frame_get_aspect_ratio( mlt_frame this );
 extern int mlt_frame_set_aspect_ratio( mlt_frame this, double value );
 extern mlt_position mlt_frame_get_position( mlt_frame this );
 extern int mlt_frame_set_position( mlt_frame this, mlt_position value );
-
 extern int mlt_frame_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable );
 extern uint8_t *mlt_frame_get_alpha_mask( mlt_frame this );
 extern int mlt_frame_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples );
-
 extern int mlt_frame_push_get_image( mlt_frame this, mlt_get_image get_image );
 extern mlt_get_image mlt_frame_pop_get_image( mlt_frame this );
 extern int mlt_frame_push_frame( mlt_frame this, mlt_frame that );
 extern mlt_frame mlt_frame_pop_frame( mlt_frame this );
 extern int mlt_frame_push_service( mlt_frame this, void *that );
 extern void *mlt_frame_pop_service( mlt_frame this );
-
 extern int mlt_frame_push_audio( mlt_frame this, void *that );
 extern void *mlt_frame_pop_audio( mlt_frame this );
-
 extern void mlt_frame_close( mlt_frame this );
 
 /* convenience functions */
index 69b02337f85aed4efcd446cee8145c3b379c9b5b..63a443fffa99a0fcb4f0a7f3828ad9e29ad299a3 100644 (file)
@@ -66,14 +66,19 @@ int mlt_producer_init( mlt_producer this, void *child )
                        mlt_properties_set_position( properties, "_position", 0.0 );
                        mlt_properties_set_double( properties, "_frame", 0 );
                        if ( normalisation == NULL || strcmp( normalisation, "NTSC" ) )
+                       {
                                mlt_properties_set_double( properties, "fps", 25.0 );
+                               mlt_properties_set_double( properties, "aspect_ratio", 72.0 / 79.0 );
+                       }
                        else
+                       {
                                mlt_properties_set_double( properties, "fps", 30000.0 / 1001.0 );
+                               mlt_properties_set_double( properties, "aspect_ratio", 128.0 / 117.0 );
+                       }
                        mlt_properties_set_double( properties, "_speed", 1.0 );
                        mlt_properties_set_position( properties, "in", 0 );
                        mlt_properties_set_position( properties, "out", 14999 );
                        mlt_properties_set_position( properties, "length", 15000 );
-                       mlt_properties_set_double( properties, "aspect_ratio", 128.0 / 117.0 );
                        mlt_properties_set( properties, "eof", "pause" );
                        mlt_properties_set( properties, "resource", "<producer>" );
 
index 2664edd7df60c2b197f5177870e531c930163f76..3fea15e27103b34aaf5ae52528978f8654b84614 100644 (file)
@@ -239,6 +239,14 @@ int mlt_properties_set( mlt_properties this, char *name, char *value )
        return error;
 }
 
+/** Set or default the property.
+*/
+
+int mlt_properties_set_or_default( mlt_properties this, char *name, char *value, char *def )
+{
+       return mlt_properties_set( this, name, value == NULL ? def : value );
+}
+
 /** Get a string value by name.
 */
 
index df66146fc8d695842e82a1548ab57186ec1c7875..6a043091f1226d59142a4fe471314a098e5559bb 100644 (file)
@@ -43,6 +43,7 @@ extern void mlt_properties_mirror( mlt_properties this, mlt_properties that );
 extern int mlt_properties_inherit( mlt_properties this, mlt_properties that );
 extern int mlt_properties_pass( mlt_properties this, mlt_properties that, char *prefix );
 extern int mlt_properties_set( mlt_properties this, char *name, char *value );
+extern int mlt_properties_set_or_default( mlt_properties this, char *name, char *value, char *def );
 extern int mlt_properties_parse( mlt_properties this, char *namevalue );
 extern char *mlt_properties_get( mlt_properties this, char *name );
 extern char *mlt_properties_get_name( mlt_properties this, int index );
index 62112d9653f20f66a572c50bb436b28f8de4b724..87252a6180297c8e7ef040a05cc017cf0121758f 100644 (file)
@@ -47,7 +47,7 @@ typedef struct
 }
 mlt_service_base;
 
-/** Friends?
+/** Private methods
 */
 
 static void mlt_service_disconnect( mlt_service this );
@@ -89,14 +89,6 @@ int mlt_service_connect_producer( mlt_service this, mlt_service producer, int in
        // Get the service base
        mlt_service_base *base = this->private;
 
-       // Does this service accept input?
-       if ( mlt_service_accepts_input( this ) == 0 )
-               return 1;
-
-       // Does the producer service accept output connections?
-       if ( mlt_service_accepts_output( producer ) == 0 )
-               return 2;
-
        // Check if the producer is already registered with this service
        for ( i = 0; i < base->count; i ++ )
                if ( base->in[ i ] == producer )
@@ -143,7 +135,7 @@ int mlt_service_connect_producer( mlt_service this, mlt_service producer, int in
 /** Disconnect this service from its consumer.
 */
 
-void mlt_service_disconnect( mlt_service this )
+static void mlt_service_disconnect( mlt_service this )
 {
        // Get the service base
        mlt_service_base *base = this->private;
@@ -155,7 +147,7 @@ void mlt_service_disconnect( mlt_service this )
 /** Associate this service to the its consumer.
 */
 
-void mlt_service_connect( mlt_service this, mlt_service that )
+static void mlt_service_connect( mlt_service this, mlt_service that )
 {
        // Get the service base
        mlt_service_base *base = this->private;
@@ -164,7 +156,6 @@ void mlt_service_connect( mlt_service this, mlt_service that )
        base->out = that;
 }
 
-
 /** Get the first connected producer service.
 */
 
@@ -180,78 +171,8 @@ mlt_service mlt_service_get_producer( mlt_service this )
        
        return producer;
 }
-
-/** Get the service state.
-*/
-
-mlt_service_state mlt_service_get_state( mlt_service this )
-{
-       mlt_service_state state = mlt_state_unknown;
-       if ( mlt_service_has_input( this ) )
-               state |= mlt_state_providing;
-       if ( mlt_service_has_output( this ) )
-               state |= mlt_state_connected;
-       if ( state != ( mlt_state_providing | mlt_state_connected ) )
-               state |= mlt_state_dormant;
-       return state;
-}
-
-/** Get the maximum number of inputs accepted.
-       Returns: -1 for many, 0 for none or n for fixed.
-*/
-
-int mlt_service_accepts_input( mlt_service this )
-{
-       if ( this->accepts_input == NULL )
-               return -1;
-       else
-               return this->accepts_input( this );
-}
-
-/** Get the maximum number of outputs accepted.
-*/
-
-int mlt_service_accepts_output( mlt_service this )
-{
-       if ( this->accepts_output == NULL )
-               return 1;
-       else
-               return this->accepts_output( this );
-}
 
-/** Determines if this service has input
-*/
-
-int mlt_service_has_input( mlt_service this )
-{
-       if ( this->has_input == NULL )
-               return 1;
-       else
-               return this->has_input( this );
-}
-
-/** Determine if this service has output
-*/
-
-int mlt_service_has_output( mlt_service this )
-{
-       mlt_service_base *base = this->private;
-       if ( this->has_output == NULL )
-               return base->out != NULL;
-       else
-               return this->has_output( this );
-}
-
-/** Check if the service is active.
-*/
-
-int mlt_service_is_active( mlt_service this )
-{
-       return !( mlt_service_get_state( this ) & mlt_state_dormant );
-}
-
-/** Obtain a frame to pass on.
+/** Default implementation of get_frame.
 */
 
 static int service_get_frame( mlt_service this, mlt_frame_ptr frame, int index )
@@ -267,6 +188,9 @@ static int service_get_frame( mlt_service this, mlt_frame_ptr frame, int index )
        return 0;
 }
 
+/** Obtain a frame.
+*/
+
 int mlt_service_get_frame( mlt_service this, mlt_frame_ptr frame, int index )
 {
        return this->get_frame( this, frame, index );
index 99d1966bc66446ec71ba937feb4accc8948daf31..afdbc623e7afc86d95e665c6a209fe775fa02928 100644 (file)
 
 #include "mlt_properties.h"
 
-/** State of a service.
-
-    Note that a service may be dormant even though it's fully connected,
-       providing or consuming.
-*/
-
-typedef enum
-{
-       mlt_state_unknown   = 0,
-       mlt_state_dormant   = 1,
-       mlt_state_connected = 2,
-       mlt_state_providing = 4,
-       mlt_state_consuming = 8
-}
-mlt_service_state;
-
 /** The interface definition for all services.
 */
 
@@ -48,10 +32,6 @@ struct mlt_service_s
        struct mlt_properties_s parent;
 
        // Protected virtual
-       int ( *accepts_input )( mlt_service this );
-       int ( *accepts_output )( mlt_service this );
-       int ( *has_input )( mlt_service this );
-       int ( *has_output )( mlt_service this );
        int ( *get_frame )( mlt_service this, mlt_frame_ptr frame, int index );
 
        // Private data
@@ -64,15 +44,10 @@ struct mlt_service_s
 
 extern int mlt_service_init( mlt_service this, void *child );
 extern int mlt_service_connect_producer( mlt_service this, mlt_service producer, int index );
-extern mlt_service_state mlt_service_get_state( mlt_service this );
+extern int mlt_service_get_frame( mlt_service this, mlt_frame_ptr frame, int index );
 extern void mlt_service_close( mlt_service this );
 
-extern int mlt_service_accepts_input( mlt_service this );
-extern int mlt_service_accepts_output( mlt_service this );
-extern int mlt_service_has_input( mlt_service this );
-extern int mlt_service_has_output( mlt_service this );
-extern int mlt_service_get_frame( mlt_service this, mlt_frame_ptr frame, int index );
-extern int mlt_service_is_active( mlt_service this );
+// I'm not sure about this one - leaving it out of docs for now (only used in consumer_westley)
 extern mlt_service mlt_service_get_producer( mlt_service this );
 
 /** Return the properties object.
index 5e061bbfdc234510945d26e6919d4a6da1775031..284c35bc5ca8d0b0587e1d11f45c0caad191adba 100644 (file)
@@ -35,6 +35,13 @@ typedef enum
 }
 mlt_image_format;
 
+typedef enum
+{
+       mlt_audio_none = 0,
+       mlt_audio_pcm
+}
+mlt_audio_format;
+
 typedef enum
 {
        mlt_whence_relative_start,
index 1cfed9be2dd7ac5559ee4217caa971e1264d38f5..3c4557ed356e486e9f002b159e3a7d74f36b18fa 100644 (file)
@@ -817,7 +817,7 @@ static int get_b_frame_image( mlt_transition this, mlt_frame b_frame, uint8_t **
        *width = geometry->sw * *width / geometry->nw;
        *height = geometry->sh * *height / geometry->nh;
 
-       x -= x % 2;
+       x &= 0xfffffffe;
 
        // optimization points - no work to do
        if ( *width < 1 || *height < 1 )
index d3d0b7acecd463971260efb55dfe75b8ad62085e..589194adea7e728fec3030e599e90ccf9af7c41f 100644 (file)
@@ -347,6 +347,9 @@ static int consumer_play_video( consumer_sdl this, mlt_frame frame )
                                                this->window_height = event.resize.h;
                                                changed = 1;
                                                break;
+                                       case SDL_QUIT:
+                                               this->running = 0;
+                                               break;
                                        case SDL_KEYDOWN:
                                                {
                                                        mlt_producer producer = mlt_properties_get_data( properties, "transport_producer", NULL );
index 3b48d274a91f5e2c421bac38631c43ffcac9142d..8e680f1bc462c56bb6d7738ce3aa7b2c4d2b38d7 100644 (file)
@@ -11,6 +11,9 @@ endif
 
 all: $(TARGET)
 
+hello:         hello.o
+                       $(CC) hello.o -o $@ -L ../framework -L ../modules -lmlt
+
 pango:         pango.o
                        $(CC) pango.o -o $@ $(LDFLAGS)
 
diff --git a/src/tests/hello.c b/src/tests/hello.c
new file mode 100644 (file)
index 0000000..d3d32df
--- /dev/null
@@ -0,0 +1,133 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <framework/mlt.h>
+
+mlt_producer create_playlist( int argc, char **argv )
+{
+       // We're creating a playlist here
+       mlt_playlist playlist = mlt_playlist_init( );
+
+       // We need the playlist properties to ensure clean up
+       mlt_properties properties = mlt_playlist_properties( playlist );
+
+       // Loop through each of the arguments
+       int i = 0;
+       for ( i = 1; i < argc; i ++ )
+       {
+               // Definie the unique key
+               char key[ 256 ];
+
+               // Create the producer
+               mlt_producer producer = mlt_factory_producer( NULL, argv[ i ] );
+
+               // Add it to the playlist
+               mlt_playlist_append( playlist, producer );
+
+               // Create a unique key for this producer
+               sprintf( key, "producer%d", i );
+
+               // Now we need to ensure the producers are destroyed
+               mlt_properties_set_data( properties, key, producer, 0, ( mlt_destructor )mlt_producer_close, NULL );
+       }
+
+       // Return the playlist as a producer
+       return mlt_playlist_producer( playlist );
+}
+
+mlt_producer create_tracks( int argc, char **argv )
+{
+       // Create the field
+       mlt_field field = mlt_field_init( );
+
+       // Obtain the multitrack
+       mlt_multitrack multitrack = mlt_field_multitrack( field );
+
+       // Obtain the tractor
+       mlt_tractor tractor = mlt_field_tractor( field );
+
+       // Obtain a composite transition
+       mlt_transition transition = mlt_factory_transition( "composite", "10%,10%:15%x15%" );
+
+       // Create track 0
+       mlt_producer track0 = create_playlist( argc, argv );
+
+       // Create the watermark track
+       mlt_producer track1 = mlt_factory_producer( "fezzik", "pango" );
+
+       // Get the length of track0
+       mlt_position length = mlt_producer_get_playtime( track0 );
+
+       // Get the properties of track1
+       mlt_properties properties = mlt_producer_properties( track1 );
+
+       // Set the properties
+       mlt_properties_set( properties, "text", "Hello\nWorld" );
+       mlt_properties_set_position( properties, "in", 0 );
+       mlt_properties_set_position( properties, "out", length - 1 );
+       mlt_properties_set_position( properties, "length", length );
+
+       // Now set the properties on the transition
+       properties = mlt_transition_properties( transition );
+       mlt_properties_set_position( properties, "in", 0 );
+       mlt_properties_set_position( properties, "out", length - 1 );
+
+       // Add our tracks to the multitrack
+       mlt_multitrack_connect( multitrack, track0, 0 );
+       mlt_multitrack_connect( multitrack, track1, 1 );
+
+       // Now plant the transition
+       mlt_field_plant_transition( field, transition, 0, 1 );
+
+       // Now set the properties on the transition
+       properties = mlt_tractor_properties( tractor );
+
+       // Ensure clean up - the first two are required since this function returns the tractor
+       mlt_properties_set_data( properties, "multitrack", multitrack, 0, ( mlt_destructor )mlt_multitrack_close, NULL );
+       mlt_properties_set_data( properties, "field", field, 0, ( mlt_destructor )mlt_field_close, NULL );
+       mlt_properties_set_data( properties, "track1", track1, 0, ( mlt_destructor )mlt_producer_close, NULL );
+       mlt_properties_set_data( properties, "transition", transition, 0, ( mlt_destructor )mlt_transition_close, NULL );
+
+       // Return the tractor
+       return mlt_tractor_producer( tractor );
+}
+
+int main( int argc, char **argv )
+{
+       // Initialise the factory
+       if ( mlt_factory_init( NULL ) == 0 )
+       {
+               // Create the default consumer
+               mlt_consumer hello = mlt_factory_consumer( NULL, NULL );
+
+               // Create a producer using the default normalising selecter
+               mlt_producer world = create_tracks( argc, argv );
+
+               // Connect the producer to the consumer
+               mlt_consumer_connect( hello, mlt_producer_service( world ) );
+
+               // Start the consumer
+               mlt_consumer_start( hello );
+
+               // Wait for the consumer to terminate
+               while( !mlt_consumer_is_stopped( hello ) )
+                       sleep( 1 );
+
+               // Close the consumer
+               mlt_consumer_close( hello );
+
+               // Close the producer
+               mlt_producer_close( world );
+
+               // Close the factory
+               mlt_factory_close( );
+       }
+       else
+       {
+               // Report an error during initialisation
+               fprintf( stderr, "Unable to locate factory modules\n" );
+       }
+
+       // End of program
+       return 0;
+}
+