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 ) );
* Reverse Polish Notation (RPN) image and audio operations
* memory pooling
- The queuing operations are used in typical frame based consumers to allow
- buffering.
+ The queuing operations are used in:
+
+ * the consumer base class;
+ * consumer implementations may require further queues.
mlt_pool:
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
Typically, only direct descendents of services need invoke these methods and
developers are encouraged to use those extensions when definining new
- services.
+ services.
mlt_producer:
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'.
+ a new producer which random noise
// Forward reference
static int producer_get_frame( mlt_service service, mlt_frame_ptr frame, int index );
none
+ mirror
+
+ Description
+
+ Provides various mirror and image reversing effects.
+
+ Constructor Argument
+
+ mirror - horizontal, vertical, diagonal, flip, flop
+
+ Initialisation Properties
+
+ int reverse - being 0 or 1
+ int in - in point
+ int out - out point
+
+ Read Only Properties
+
+ none
+
+ Mutable Properties
+
+ none
+
+ Dependencies
+
+ none
+
+ Known Bugs
+
+ none
+
+
obscure
Description
return error;
}
+/** Create a new producer.
+*/
+
+mlt_producer mlt_producer_new( )
+{
+ mlt_producer this = malloc( sizeof( struct mlt_producer_s ) );
+ mlt_producer_init( this, NULL );
+ return this;
+}
+
/** Get the parent service object.
*/
*/
extern int mlt_producer_init( mlt_producer this, void *child );
+extern mlt_producer mlt_producer_new( );
extern mlt_service mlt_producer_service( mlt_producer this );
extern mlt_properties mlt_producer_properties( mlt_producer this );
extern int mlt_producer_seek( mlt_producer this, mlt_position position );
static inline void mlt_properties_do_mirror( mlt_properties this, char *name )
{
property_list *list = this->private;
- if ( list->mirror != NULL && strcmp( name, "in" ) && strcmp( name, "out" ) )
+ if ( list->mirror != NULL )
{
char *value = mlt_properties_get( this, name );
if ( value != NULL )
if ( got_picture )
{
if ( pkt.pts != AV_NOPTS_VALUE && pkt.pts != 0 )
- {
current_time = ( double )pkt.pts / 1000000.0;
- }
else
current_time = real_timecode;
TARGET = ../libmltcore.so
OBJS = factory.o \
+ producer_colour.o \
+ producer_noise.o \
producer_ppm.o \
filter_brightness.o \
filter_channelcopy.o \
- filter_greyscale.o \
filter_gamma.o \
+ filter_greyscale.o \
filter_luma.o \
+ filter_mirror.o \
filter_obscure.o \
filter_region.o \
filter_resize.o \
filter_volume.o \
filter_watermark.o \
- producer_colour.o \
transition_composite.o \
transition_luma.o \
transition_mix.o \
cat << EOF >> ../producers.dat
colour libmltcore.so
+noise libmltcore.so
ppm libmltcore.so
EOF
gamma libmltcore.so
greyscale libmltcore.so
luma libmltcore.so
+mirror libmltcore.so
obscure libmltcore.so
region libmltcore.so
resize libmltcore.so
#include <string.h>
+#include "producer_colour.h"
+#include "producer_noise.h"
#include "producer_ppm.h"
#include "filter_brightness.h"
#include "filter_channelcopy.h"
#include "filter_gamma.h"
-#include "filter_luma.h"
#include "filter_greyscale.h"
+#include "filter_luma.h"
+#include "filter_mirror.h"
#include "filter_obscure.h"
#include "filter_resize.h"
#include "filter_region.h"
#include "filter_volume.h"
#include "filter_watermark.h"
-#include "producer_colour.h"
#include "transition_composite.h"
#include "transition_luma.h"
#include "transition_mix.h"
{
if ( !strcmp( id, "colour" ) )
return producer_colour_init( arg );
+ if ( !strcmp( id, "noise" ) )
+ return producer_noise_init( arg );
if ( !strcmp( id, "ppm" ) )
return producer_ppm_init( arg );
return NULL;
return filter_greyscale_init( arg );
if ( !strcmp( id, "luma" ) )
return filter_luma_init( arg );
+ if ( !strcmp( id, "mirror" ) )
+ return filter_mirror_init( arg );
if ( !strcmp( id, "obscure" ) )
return filter_obscure_init( arg );
if ( !strcmp( id, "region" ) )
--- /dev/null
+/*
+ * filter_mirror.c -- mirror filter
+ * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
+ * Author: Charles Yates <charles.yates@pandora.be>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "filter_mirror.h"
+
+#include <framework/mlt_frame.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/** Do it :-).
+*/
+
+static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
+{
+ // Pop the mirror filter from the stack
+ mlt_filter this = mlt_frame_pop_service( frame );
+
+ // Get the mirror type
+ mlt_properties properties = mlt_filter_properties( this );
+
+ // Get the properties
+ char *mirror = mlt_properties_get( properties, "mirror" );
+
+ // Determine if reverse is required
+ int reverse = mlt_properties_get_int( properties, "reverse" );
+
+ // Get the image
+ int error = mlt_frame_get_image( frame, image, format, width, height, 1 );
+
+ // If we have an image of the right colour space
+ if ( error == 0 && *format == mlt_image_yuv422 )
+ {
+ // We'll KISS here
+ int hh = *height / 2;
+
+ if ( !strcmp( mirror, "horizontal" ) )
+ {
+ uint8_t *p = NULL;
+ uint8_t *q = NULL;
+ int i;
+ for ( i = 0; i < *height; i ++ )
+ {
+ p = ( uint8_t * )*image + i * *width * 2;
+ q = p + *width * 2;
+ if ( !reverse )
+ {
+ while ( p != q )
+ {
+ *p ++ = *( q - 2 );
+ *p ++ = *( q - 3 );
+ *p ++ = *( q - 4 );
+ *p ++ = *( q - 1 );
+ q -= 4;
+ }
+ }
+ else
+ {
+ while ( p != q )
+ {
+ *( q - 2 ) = *p ++;
+ *( q - 3 ) = *p ++;
+ *( q - 4 ) = *p ++;
+ *( q - 1 ) = *p ++;
+ q -= 4;
+ }
+ }
+ }
+ }
+ else if ( !strcmp( mirror, "vertical" ) )
+ {
+ uint16_t *end = ( uint16_t *)*image + *width * *height;
+ uint16_t *p = NULL;
+ uint16_t *q = NULL;
+ int i;
+ int j;
+ for ( i = 0; i < hh; i ++ )
+ {
+ p = ( uint16_t * )*image + i * *width;
+ q = end - i * *width;
+ j = *width;
+ if ( !reverse )
+ {
+ while ( j -- )
+ *p ++ = *q ++;
+ }
+ else
+ {
+ while ( j -- )
+ *q ++ = *p ++;
+ }
+ }
+ }
+ else if ( !strcmp( mirror, "diagonal" ) )
+ {
+ uint8_t *end = ( uint8_t *)*image + *width * *height * 2;
+ uint8_t *p = NULL;
+ uint8_t *q = NULL;
+ int i;
+ int j;
+ for ( i = 0; i < *height; i ++ )
+ {
+ p = ( uint8_t * )*image + i * *width * 2;
+ q = end - i * *width * 2;
+ j = ( ( *width * ( *height - i ) ) / *height ) / 2;
+ if ( !reverse )
+ {
+ while ( j -- )
+ {
+ *p ++ = *( q - 2 );
+ *p ++ = *( q - 3 );
+ *p ++ = *( q - 4 );
+ *p ++ = *( q - 1 );
+ q -= 4;
+ }
+ }
+ else
+ {
+ while ( j -- )
+ {
+ *( q - 2 ) = *p ++;
+ *( q - 3 ) = *p ++;
+ *( q - 4 ) = *p ++;
+ *( q - 1 ) = *p ++;
+ q -= 4;
+ }
+ }
+ }
+ }
+ else if ( !strcmp( mirror, "flip" ) )
+ {
+ uint8_t t[ 4 ];
+ uint8_t *p = NULL;
+ uint8_t *q = NULL;
+ int i;
+ for ( i = 0; i < *height; i ++ )
+ {
+ p = ( uint8_t * )*image + i * *width * 2;
+ q = p + *width * 2;
+ while ( p != q )
+ {
+ t[ 0 ] = p[ 0 ];
+ t[ 1 ] = p[ 1 ];
+ t[ 2 ] = p[ 2 ];
+ t[ 3 ] = p[ 3 ];
+ *p ++ = *( q - 2 );
+ *p ++ = *( q - 3 );
+ *p ++ = *( q - 4 );
+ *p ++ = *( q - 1 );
+ *( -- q ) = t[ 3 ];
+ *( -- q ) = t[ 0 ];
+ *( -- q ) = t[ 1 ];
+ *( -- q ) = t[ 2 ];
+ }
+ }
+ }
+ else if ( !strcmp( mirror, "flop" ) )
+ {
+ uint16_t *end = ( uint16_t *)*image + *width * *height;
+ uint16_t *p = NULL;
+ uint16_t *q = NULL;
+ uint16_t t;
+ int i;
+ int j;
+ for ( i = 0; i < hh; i ++ )
+ {
+ p = ( uint16_t * )*image + i * *width;
+ q = end - i * *width;
+ j = *width;
+ while ( j -- )
+ {
+ t = *p;
+ *p ++ = *q;
+ *q ++ = t;
+ }
+ }
+ }
+ }
+
+ // Return the error
+ return error;
+}
+
+/** Filter processing.
+*/
+
+static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
+{
+ // Push the service on to the stack
+ mlt_frame_push_service( frame, this );
+
+ // Push the filter method on to the stack
+ mlt_frame_push_service( frame, filter_get_image );
+
+ return frame;
+}
+
+/** Constructor for the filter.
+*/
+
+mlt_filter filter_mirror_init( void *arg )
+{
+ // Construct a new filter
+ mlt_filter this = mlt_filter_new( );
+
+ // If we have a filter, initialise it
+ if ( this != NULL )
+ {
+ // Get the properties
+ mlt_properties properties = mlt_filter_properties( this );
+
+ // Set the default mirror type
+ mlt_properties_set_or_default( properties, "mirror", arg, "horizontal" );
+
+ // Assign the process method
+ this->process = filter_process;
+ }
+
+ // Return the filter
+ return this;
+}
+
--- /dev/null
+/*
+ * filter_mirror.h -- mirror filter
+ * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
+ * Author: Charles Yates <charles.yates@pandora.be>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _FILTER_MIRROR_H_
+#define _FILTER_MIRROR_H_
+
+#include <framework/mlt_filter.h>
+
+extern mlt_filter filter_mirror_init( void *arg );
+
+#endif
// Make sure the producer is in the correct position
mlt_producer_seek( producer, position );
+ // Resetting position to appease the composite transition
+ mlt_frame_set_position( frame, position );
+
// Get the b frame and process with composite if successful
if ( mlt_service_get_frame( service, &b_frame, 0 ) == 0 )
mlt_transition_process( composite, frame, b_frame );
// Color the image
rgba_color color = parse_color( mlt_properties_get( producer_props, "resource" ) );
uint8_t y, u, v;
- int i;
+ int i = 0;
RGB2YUV( color.r, color.g, color.b, y, u, v );
- color.r = y;
- color.g = u;
- color.b = y;
- color.a = v;
- for ( i = 0; i < size; i += 4 )
- memcpy( &image[ i ], &color, 4 );
+
+ while ( i < size )
+ {
+ image[ i ++ ] = y;
+ image[ i ++ ] = u;
+ image[ i ++ ] = y;
+ image[ i ++ ] = v;
+ }
}
// Update the frame
mlt_properties_set_int( properties, "progressive", 1 );
// colour is an alias for resource
+ // CY: Do we really need this?
if ( mlt_properties_get( producer_props, "colour" ) != NULL )
mlt_properties_set( producer_props, "resource", mlt_properties_get( producer_props, "colour" ) );
--- /dev/null
+/*
+ * producer_noise.c -- noise generating producer
+ * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
+ * Author: Charles Yates <charles.yates@pandora.be>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "producer_noise.h"
+#include <framework/mlt_frame.h>
+#include <framework/mlt_pool.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/** Random number generator
+*/
+
+static unsigned int seed_x = 521288629;
+static unsigned int seed_y = 362436069;
+
+static unsigned inline int fast_rand( )
+{
+ static unsigned int a = 18000, b = 30903;
+ seed_x = a * ( seed_x & 65535 ) + ( seed_x >> 16 );
+ seed_y = b * ( seed_y & 65535 ) + ( seed_y >> 16 );
+ return ( ( seed_x << 16 ) + ( seed_y & 65535 ) );
+}
+
+// Foward declarations
+static int producer_get_frame( mlt_producer this, mlt_frame_ptr frame, int index );
+
+/** Initialise.
+*/
+
+mlt_producer producer_noise_init( void *arg )
+{
+ // Create a new producer object
+ mlt_producer this = mlt_producer_new( );
+
+ // Initialise the producer
+ if ( this != NULL )
+ {
+ // Callback registration
+ this->get_frame = producer_get_frame;
+ }
+
+ return this;
+}
+
+static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
+{
+ // Obtain properties of frame
+ mlt_properties properties = mlt_frame_properties( frame );
+
+ // Calculate the size of the image
+ int size = *width * *height * 2;
+
+ // Set the format being returned
+ *format = mlt_image_yuv422;
+
+ // Allocate the image
+ *buffer = mlt_pool_alloc( size );
+
+ // Update the frame
+ mlt_properties_set_data( properties, "image", *buffer, size, mlt_pool_release, NULL );
+ mlt_properties_set_int( properties, "width", *width );
+ mlt_properties_set_int( properties, "height", *height );
+
+ // Before we write to the image, make sure we have one
+ if ( *buffer != NULL )
+ {
+ // Calculate the end of the buffer
+ uint8_t *p = *buffer + *width * *height * 2;
+
+ // Value to hold a random number
+ uint32_t value;
+
+ // Generate random noise
+ while ( p != *buffer )
+ {
+ value = fast_rand( );
+ *( -- p ) = 128;
+ *( -- p ) = value & 0xff;
+ *( -- p ) = 128;
+ *( -- p ) = ( ( value & 0xff00 ) >> 8 ) & 0xf0;
+ }
+ }
+
+ return 0;
+}
+
+static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
+{
+ // Get the frame properties
+ mlt_properties properties = mlt_frame_properties( frame );
+
+ int size = 0;
+
+ // Correct the returns if necessary
+ *samples = *samples <= 0 ? 1920 : *samples;
+ *channels = *channels <= 0 ? 2 : *channels;
+ *frequency = *frequency <= 0 ? 48000 : *frequency;
+
+ // Calculate the size of the buffer
+ size = *samples * *channels * sizeof( int16_t );
+
+ // Allocate the buffer
+ *buffer = mlt_pool_alloc( size );
+
+ // Make sure we got one and fill it
+ if ( *buffer != NULL )
+ {
+ int16_t *p = *buffer + size / 2;
+ while ( p != *buffer )
+ *( -- p ) = fast_rand( ) & 0xff;
+ }
+
+ // Set the buffer for destruction
+ mlt_properties_set_data( properties, "audio", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL );
+
+ return 0;
+}
+
+static int producer_get_frame( mlt_producer this, mlt_frame_ptr frame, int index )
+{
+ // Generate a frame
+ *frame = mlt_frame_init( );
+
+ // Check that we created a frame and initialise it
+ if ( *frame != NULL )
+ {
+ // Obtain properties of frame
+ mlt_properties properties = mlt_frame_properties( *frame );
+
+ // Aspect ratio is 1?
+ mlt_properties_set_double( properties, "aspect_ratio", 1.0 );
+
+ // Set producer-specific frame properties
+ mlt_properties_set_int( properties, "progressive", 1 );
+
+ // Update timecode on the frame we're creating
+ mlt_frame_set_position( *frame, mlt_producer_position( this ) );
+
+ // Push the get_image method
+ mlt_frame_push_get_image( *frame, producer_get_image );
+
+ // Specify the audio
+ ( *frame )->get_audio = producer_get_audio;
+ }
+
+ // Calculate the next timecode
+ mlt_producer_prepare_next( this );
+
+ return 0;
+}
+
+
--- /dev/null
+/*
+ * producer_noise.h -- noise generating producer
+ * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
+ * Author: Charles Yates <charles.yates@pandora.be>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _PRODUCER_NOISE_H_
+#define _PRODUCER_NOISE_H_
+
+#include <framework/mlt_producer.h>
+
+extern mlt_producer producer_noise_init( void *arg );
+
+#endif
{
mlt_producer result = NULL;
+ // 0th Line - check for service:resource handling
+ if ( strchr( file, ':' ) )
+ {
+ char *temp = strdup( file );
+ char *service = temp;
+ char *resource = strchr( temp, ':' );
+ *resource ++ = '\0';
+ result = mlt_factory_producer( service, resource );
+ free( temp );
+ }
+
// 1st Line preferences
- if ( strstr( file, ".inigo" ) )
- result = mlt_factory_producer( "inigo_file", file );
- else if ( strstr( file, ".mpg" ) )
- result = mlt_factory_producer( "mcmpeg", file );
- else if ( strstr( file, ".mpeg" ) )
- result = mlt_factory_producer( "mcmpeg", file );
- else if ( strstr( file, ".dv" ) )
- result = mlt_factory_producer( "mcdv", file );
- else if ( strstr( file, ".dif" ) )
- result = mlt_factory_producer( "mcdv", file );
- else if ( strstr( file, ".jpg" ) )
- result = mlt_factory_producer( "pixbuf", file );
- else if ( strstr( file, ".JPG" ) )
- result = mlt_factory_producer( "pixbuf", file );
- else if ( strstr( file, ".jpeg" ) )
- result = mlt_factory_producer( "pixbuf", file );
- else if ( strstr( file, ".png" ) )
- result = mlt_factory_producer( "pixbuf", file );
- else if ( strstr( file, ".svg" ) )
- result = mlt_factory_producer( "pixbuf", file );
- else if ( strstr( file, ".txt" ) )
- result = mlt_factory_producer( "pango", file );
- else if ( strstr( file, ".westley" ) )
- result = mlt_factory_producer( "westley", file );
- else if ( strstr( file, ".ogg" ) )
- result = mlt_factory_producer( "vorbis", file );
+ if ( result == NULL )
+ {
+ if ( strstr( file, ".inigo" ) )
+ result = mlt_factory_producer( "inigo_file", file );
+ else if ( strstr( file, ".mpg" ) )
+ result = mlt_factory_producer( "mcmpeg", file );
+ else if ( strstr( file, ".mpeg" ) )
+ result = mlt_factory_producer( "mcmpeg", file );
+ else if ( strstr( file, ".dv" ) )
+ result = mlt_factory_producer( "mcdv", file );
+ else if ( strstr( file, ".dif" ) )
+ result = mlt_factory_producer( "mcdv", file );
+ else if ( strstr( file, ".jpg" ) )
+ result = mlt_factory_producer( "pixbuf", file );
+ else if ( strstr( file, ".JPG" ) )
+ result = mlt_factory_producer( "pixbuf", file );
+ else if ( strstr( file, ".jpeg" ) )
+ result = mlt_factory_producer( "pixbuf", file );
+ else if ( strstr( file, ".png" ) )
+ result = mlt_factory_producer( "pixbuf", file );
+ else if ( strstr( file, ".svg" ) )
+ result = mlt_factory_producer( "pixbuf", file );
+ else if ( strstr( file, ".txt" ) )
+ result = mlt_factory_producer( "pango", file );
+ else if ( strstr( file, ".westley" ) )
+ result = mlt_factory_producer( "westley", file );
+ else if ( strstr( file, ".ogg" ) )
+ result = mlt_factory_producer( "vorbis", file );
+ }
// 2nd Line fallbacks
if ( result == NULL )
// 3rd line fallbacks
if ( result == NULL )
- result = mlt_factory_producer( "avformat", file +
- ( strncmp( file, "avformat:", 9 ) ? 0 : 9 ) );
-
- // 4th - allow explicit construction
- if ( result == NULL )
- {
- char *arg = strchr( file, ':' );
- if ( arg )
- {
- arg[0] = 0;
- arg++;
- }
- result = mlt_factory_producer( file, arg );
- }
+ result = mlt_factory_producer( "avformat", file );
return result;
}
// 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 );
+ // Create the watermark track
+ mlt_producer track1 = mlt_factory_producer( "fezzik", "pango" );
+
// Get the properties of track1
mlt_properties properties = mlt_producer_properties( track1 );
// 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
+ // Ensure clean up and set properties correctly
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 );
+ mlt_properties_set_position( properties, "length", length );
+ mlt_properties_set_position( properties, "out", length - 1 );
// Return the tractor
return mlt_tractor_producer( tractor );