Beispiel #1
0
static void attach_normalisers( mlt_profile profile, mlt_producer producer )
{
	// Loop variable
	int i;

	// Tokeniser
	mlt_tokeniser tokeniser = mlt_tokeniser_init( );

	// We only need to load the normalising properties once
	if ( normalisers == NULL )
	{
		char temp[ 1024 ];
		sprintf( temp, "%s/core/loader.ini", mlt_environment( "MLT_DATA" ) );
		normalisers = mlt_properties_load( temp );
		mlt_factory_register_for_clean_up( normalisers, ( mlt_destructor )mlt_properties_close );
	}

	// Apply normalisers
	for ( i = 0; i < mlt_properties_count( normalisers ); i ++ )
	{
		int j = 0;
		int created = 0;
		char *value = mlt_properties_get_value( normalisers, i );
		mlt_tokeniser_parse_new( tokeniser, value, "," );
		for ( j = 0; !created && j < mlt_tokeniser_count( tokeniser ); j ++ )
			create_filter( profile, producer, mlt_tokeniser_get_string( tokeniser, j ), &created );
	}

	// Close the tokeniser
	mlt_tokeniser_close( tokeniser );
}
Beispiel #2
0
static void query_services( mlt_repository repo, mlt_service_type type )
{
	mlt_properties services = NULL;
	const char *typestr = NULL;
	switch ( type )
	{
		case consumer_type:
			services = mlt_repository_consumers( repo );
			typestr = "consumers";
			break;
		case filter_type:
			services = mlt_repository_filters( repo );
			typestr = "filters";
			break;
		case producer_type:
			services = mlt_repository_producers( repo );
			typestr = "producers";
			break;
		case transition_type:
			services = mlt_repository_transitions( repo );
			typestr = "transitions";
			break;
		default:
			return;
	}
	fprintf( stderr, "---\n%s:\n", typestr );
	if ( services )
	{
		int j;
		for ( j = 0; j < mlt_properties_count( services ); j++ )
			fprintf( stderr, "  - %s\n", mlt_properties_get_name( services, j ) );
	}
	fprintf( stderr, "...\n" );
}
Beispiel #3
0
static mlt_filter obtain_filter( mlt_filter filter, char *type )
{
	// Result to return
	mlt_filter result = NULL;

	// Miscelaneous variable
	int i = 0;
	int type_len = strlen( type );

	// Get the properties of the data show filter
	mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter );

	// Get the profile properties
	mlt_properties profile_properties = mlt_properties_get_data( filter_properties, "profile_properties", NULL );

	// Obtain the profile_properties if we haven't already
	if ( profile_properties == NULL )
	{
		char temp[ 512 ];

		// Get the profile requested
		char *profile = mlt_properties_get( filter_properties, "resource" );

		// If none is specified, pick up the default for this normalisation
		if ( profile == NULL )
			sprintf( temp, "%s/feeds/%s/data_fx.properties", mlt_environment( "MLT_DATA" ), mlt_environment( "MLT_NORMALISATION" ) );
		else if ( strchr( profile, '%' ) )
			sprintf( temp, "%s/feeds/%s/%s", mlt_environment( "MLT_DATA" ), mlt_environment( "MLT_NORMALISATION" ), strchr( profile, '%' ) + 1 );
		else
		{
			strncpy( temp, profile, sizeof( temp ) );
			temp[ sizeof( temp ) - 1 ] = '\0';
		}

		// Load the specified profile or use the default
		profile_properties = mlt_properties_load( temp );

		// Store for later retrieval
		mlt_properties_set_data( filter_properties, "profile_properties", profile_properties, 0, ( mlt_destructor )mlt_properties_close, NULL );
	}

	if ( profile_properties != NULL )
	{
		for ( i = 0; i < mlt_properties_count( profile_properties ); i ++ )
		{
			char *name = mlt_properties_get_name( profile_properties, i );
			char *value = mlt_properties_get_value( profile_properties, i );
	
			if ( result == NULL && !strcmp( name, type ) && result == NULL )
				result = mlt_factory_filter( mlt_service_profile( MLT_FILTER_SERVICE( filter ) ), value, NULL );
			else if ( result != NULL && !strncmp( name, type, type_len ) && name[ type_len ] == '.' )
				mlt_properties_set( MLT_FILTER_PROPERTIES( result ), name + type_len + 1, value );
			else if ( result != NULL )
				break;
		}
	}

	return result;
}
Beispiel #4
0
void mlt_cache_purge( mlt_cache cache, void *object )
{
    pthread_mutex_lock( &cache->mutex );
    if ( cache && object )
    {
        int i, j;
        void **alt = cache->current == cache->A ? cache->B : cache->A;

        for ( i = 0, j = 0; i < cache->count; i++ )
        {
            void *o = cache->current[ i ];

            if ( o == object )
            {
                pthread_mutex_unlock( &cache->mutex );
                cache_object_close( cache, o, NULL );
                pthread_mutex_lock( &cache->mutex );
            }
            else
            {
                alt[ j++ ] = o;
            }
        }
        cache->count = j;
        cache->current = alt;

        // Remove the object's data from the active list regardless of refcount
        char key[19];
        sprintf( key, "%p", object );
        mlt_cache_item item = mlt_properties_get_data( cache->active, key, NULL );
        if ( item && item->destructor )
        {
            item->destructor( item->data );
            item->data = NULL;
            item->destructor = NULL;
            mlt_properties_set_data( cache->active, key, NULL, 0, NULL, NULL );
        }

        // Remove the object's items from the garbage collection regardless of refcount
        i = mlt_properties_count( cache->garbage );
        while ( i-- )
        {
            item = mlt_properties_get_data_at( cache->garbage, i, NULL );
            if ( object == item->object && item->destructor )
            {
                sprintf( key, "%p", item->data );
                item->destructor( item->data );
                item->data = NULL;
                item->destructor = NULL;
                mlt_properties_set_data( cache->garbage, key, NULL, 0, NULL, NULL );
            }
        }
    }
    pthread_mutex_unlock( &cache->mutex );
}
Beispiel #5
0
static void query_presets()
{
    mlt_properties presets = mlt_repository_presets();
    fprintf( stdout, "---\npresets:\n" );
    if ( presets )
    {
        int j;
        for ( j = 0; j < mlt_properties_count( presets ); j++ )
            fprintf( stdout, "  - %s\n", mlt_properties_get_name( presets, j ) );
    }
    fprintf( stdout, "...\n" );
    mlt_properties_close( presets );
}
Beispiel #6
0
std::ostream& operator <<(std::ostream& os, mlt_properties props)
{
	int count = mlt_properties_count(props);
	os<<"{"<<endl;
	for ( int i=0; i<count; i++) {
		char buf[1024];
		const char* name = mlt_properties_get_name(props, i);
		snprintf(buf, sizeof(buf), "%s: %s\n", name, mlt_properties_get(props, name));
		os << buf ;
	}
	os<<"}"<<endl;
	return os;
}
Beispiel #7
0
static void query_profiles()
{
    mlt_properties profiles = mlt_profile_list();
    fprintf( stdout, "---\nprofiles:\n" );
    if ( profiles )
    {
        int j;
        for ( j = 0; j < mlt_properties_count( profiles ); j++ )
            fprintf( stdout, "  - %s\n", mlt_properties_get_name( profiles, j ) );
    }
    fprintf( stdout, "...\n" );
    mlt_properties_close( profiles );
}
Beispiel #8
0
void mlt_service_cache_purge( mlt_service self )
{
	mlt_properties caches = mlt_properties_get_data( mlt_global_properties(), "caches", NULL );

	if ( caches )
	{
		int i = mlt_properties_count( caches );
		while ( i-- )
		{
			mlt_cache_purge( mlt_properties_get_data_at( caches, i, NULL ), self );
			mlt_properties_set_data( mlt_global_properties(), mlt_properties_get_name( caches, i ), NULL, 0, NULL, NULL );
		}
	}
}
Beispiel #9
0
static void load_filenames( producer_qimage self, mlt_properties properties )
{
	char *filename = mlt_properties_get( properties, "resource" );
	self->filenames = mlt_properties_new( );

	if (!load_svg( self, properties, filename ) &&
		!load_sequence( self, properties, filename ) &&
		!load_sequence2( self, properties, filename ) &&
		!load_folder( self, properties, filename ) )
	{
		mlt_properties_set( self->filenames, "0", filename );
	}
	self->count = mlt_properties_count( self->filenames );
}
Beispiel #10
0
static void load_filenames( producer_pixbuf self, mlt_properties properties )
{
	char *filename = mlt_properties_get( properties, "resource" );
	self->filenames = mlt_properties_new( );

	if (!load_svg( self, properties, filename ) &&
		!load_sequence_querystring( self, properties, filename ) &&
		!load_sequence_sprintf( self, properties, filename ) &&
		!load_sequence_deprecated( self, properties, filename ) &&
		!load_folder( self, properties, filename ) )
	{
		mlt_properties_set( self->filenames, "0", filename );
	}
	self->count = mlt_properties_count( self->filenames );
}
Beispiel #11
0
static void check_thread_safe( mlt_properties properties, const char *name )
{
	char dirname[PATH_MAX];
	snprintf( dirname, PATH_MAX, "%s/frei0r/not_thread_safe.txt", mlt_environment( "MLT_DATA" ) );
	mlt_properties not_thread_safe = mlt_properties_load( dirname );
	int i;

	for ( i = 0; i < mlt_properties_count( not_thread_safe ); i++ )
	{
		if ( strcmp( name, mlt_properties_get_name( not_thread_safe, i ) ) == 0 )
		{
			mlt_properties_set_int( properties, "_not_thread_safe", 1 );
			break;
		}
	}
	mlt_properties_close( not_thread_safe );
}
Beispiel #12
0
static void list_presets( mlt_properties properties, const char *path, const char *dirname )
{
	DIR *dir = opendir( dirname );

	if ( dir )
	{
		struct dirent *de = readdir( dir );
		char fullname[ PATH_MAX ];

		while ( de != NULL )
		{
			if ( de->d_name[0] != '.' && de->d_name[strlen( de->d_name ) - 1] != '~' )
			{
				struct stat info;

				snprintf( fullname, sizeof(fullname), "%s/%s", dirname, de->d_name );
				stat( fullname, &info );
				if ( S_ISDIR( info.st_mode ) )
				{
					// recurse into subdirectories
					char sub[ PATH_MAX ];
					if ( path )
						snprintf( sub, sizeof(sub), "%s/%s", path, de->d_name );
					else
						strncpy( sub, de->d_name, sizeof(sub) );
					list_presets( properties, sub, fullname );
				}
				else
				{
					// load the preset
					mlt_properties preset = mlt_properties_load( fullname );
					if ( preset && mlt_properties_count( preset ) )
					{
						snprintf( fullname, 1024, "%s/%s", path, de->d_name );
						mlt_properties_set_data( properties, fullname, preset, 0, (mlt_destructor) mlt_properties_close, NULL );
					}
				}
			}
			de = readdir( dir );
		}
		closedir( dir );
	}
}
Beispiel #13
0
mlt_properties mlt_profile_list( )
{
	char *filename = NULL;
	const char *prefix = getenv( "MLT_PROFILES_PATH" );
	mlt_properties properties = mlt_properties_new();
	mlt_properties dir = mlt_properties_new();
	int sort = 1;
	const char *wildcard = NULL;
	int i;

	// Load from $datadir/mlt/profiles if no env var
	if ( prefix == NULL )
	{
		prefix = mlt_environment( "MLT_DATA" );
		filename = calloc( 1, strlen( prefix ) + strlen( PROFILES_DIR ) + 1 );
		strcpy( filename, prefix );
		strcat( filename, PROFILES_DIR );
		prefix = filename;
	}

	mlt_properties_dir_list( dir, prefix, wildcard, sort );

	for ( i = 0; i < mlt_properties_count( dir ); i++ )
	{
		char *filename = mlt_properties_get_value( dir, i );
		char *profile_name = basename( filename );
		if ( profile_name[0] != '.' && strcmp( profile_name, "Makefile" ) &&
		     profile_name[ strlen( profile_name ) - 1 ] != '~' )
		{
			mlt_properties profile = mlt_properties_load( filename );
			if ( profile )
			{
				mlt_properties_set_data( properties, profile_name, profile, 0,
					(mlt_destructor) mlt_properties_close, NULL );
			}
		}
	}
	mlt_properties_close( dir );
	if ( filename )
		free( filename );

	return properties;
}
Beispiel #14
0
static int load_sequence_sprintf( producer_qimage self, mlt_properties properties, const char *filename )
{
	int result = 0;

	// Obtain filenames with pattern
	if ( strchr( filename, '%' ) != NULL )
	{
		// handle picture sequences
		int i = mlt_properties_get_int( properties, "begin" );
		int gap = 0;
		char full[1024];
		int keyvalue = 0;
		char key[ 50 ];

		while ( gap < 100 )
		{
			struct stat buf;
			snprintf( full, 1023, filename, i ++ );
			if ( stat( full, &buf ) == 0 )
			{
				sprintf( key, "%d", keyvalue ++ );
				mlt_properties_set( self->filenames, key, full );
				gap = 0;
			}
			else
			{
				gap ++;
			}
		}
		if ( mlt_properties_count( self->filenames ) > 0 )
		{
			mlt_properties_set_int( properties, "ttl", 1 );
			result = 1;
		}
	}
	return result;
}
Beispiel #15
0
static int is_service_hidden(mlt_repository repo, mlt_service_type type, const char *service_name )
{
    mlt_properties metadata = NULL;
    mlt_properties tags = NULL;
    metadata = mlt_repository_metadata(repo, type, service_name);

    if( metadata )
    {
        tags = mlt_properties_get_data( metadata, "tags", NULL );
        if( tags )
        {
            int k;
            for ( k = 0; k < mlt_properties_count( tags ); k++ )
            {
                const char* value = mlt_properties_get_value(tags, k);
                if( !strcmp("Hidden", value) )
                {
                    return 1;
                }
            }
        }
    }
    return 0;
}
Beispiel #16
0
mlt_producer producer_framebuffer_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
{
	if ( !arg ) return NULL;
	mlt_producer producer = NULL;
	producer = calloc( 1, sizeof( struct mlt_producer_s ) );
	if ( !producer )
		return NULL;

	if ( mlt_producer_init( producer, NULL ) )
	{
		free( producer );
		return NULL;
	}

	// Wrap loader
	mlt_producer real_producer;
	
	// Check if a speed was specified.
	/** 

	* Speed must be appended to the filename with '?'. To play your video at 50%:
	 melt framebuffer:my_video.mpg?0.5

	* Stroboscope effect can be obtained by adding a stobe=x parameter, where
	 x is the number of frames that will be ignored.

	* You can play the movie backwards by adding reverse=1

	* You can freeze the clip at a determined position by adding freeze=frame_pos
	  add freeze_after=1 to freeze only paste position or freeze_before to freeze before it

	**/

	double speed = 0.0;
	char *props = strdup( arg );
	char *ptr = strrchr( props, '?' );
	
	if ( ptr )
	{
		speed = atof( ptr + 1 );
		if ( speed != 0.0 )
			// If speed was valid, then strip it and the delimiter.
			// Otherwise, an invalid speed probably means this '?' was not a delimiter.
			*ptr = '\0';
	}
		
	real_producer = mlt_factory_producer( profile, "abnormal", props );
	free( props );

	if (speed == 0.0) speed = 1.0;

	if ( producer != NULL && real_producer != NULL)
	{
		// Get the properties of this producer
		mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );

		mlt_properties_set( properties, "resource", arg);

		// Store the producer and fitler
		mlt_properties_set_data( properties, "producer", real_producer, 0, ( mlt_destructor )mlt_producer_close, NULL );

		// Grab some stuff from the real_producer
		mlt_properties_pass_list( properties, MLT_PRODUCER_PROPERTIES( real_producer ), "length, width, height, aspect_ratio" );

		if ( speed < 0 )
		{
			speed = -speed;
			mlt_properties_set_int( properties, "reverse", 1 );
		}

		if ( speed != 1.0 )
		{
			double real_length = ( (double)  mlt_producer_get_length( real_producer ) ) / speed;
			mlt_properties_set_position( properties, "length", real_length );
			mlt_properties real_properties = MLT_PRODUCER_PROPERTIES( real_producer );
			const char* service = mlt_properties_get( real_properties, "mlt_service" );
			if ( service && !strcmp( service, "avformat" ) )
			{
				int n = mlt_properties_count( real_properties );
				int i;
				for ( i = 0; i < n; i++ )
				{
					if ( strstr( mlt_properties_get_name( real_properties, i ), "stream.frame_rate" ) )
					{
						double source_fps = mlt_properties_get_double( real_properties, mlt_properties_get_name( real_properties, i ) );
						if ( source_fps > mlt_profile_fps( profile ) )
						{
							mlt_properties_set_double( real_properties, "force_fps", source_fps * speed );
							mlt_properties_set_position( real_properties, "length", real_length );
							mlt_properties_set_position( real_properties, "out", real_length - 1 );
							speed = 1.0;
						}
						break;
					}
				}
			}
		}
		mlt_properties_set_position( properties, "out", mlt_producer_get_length( producer ) - 1 );

		// Since we control the seeking, prevent it from seeking on its own
		mlt_producer_set_speed( real_producer, 0 );
		mlt_producer_set_speed( producer, speed );

		// Override the get_frame method
		producer->get_frame = producer_get_frame;
	}
	else
	{
		if ( producer )
			mlt_producer_close( producer );
		if ( real_producer )
			mlt_producer_close( real_producer );

		producer = NULL;
	}
	return producer;
}
Beispiel #17
0
int mlt_producer_optimise( mlt_producer self )
{
	int error = 1;
	mlt_parser parser = mlt_parser_new( );
	if ( parser != NULL )
	{
		int i = 0, j = 0, k = 0;
		mlt_properties properties = mlt_parser_properties( parser );
		mlt_properties producers = mlt_properties_new( );
		mlt_deque stack = mlt_deque_init( );
		mlt_properties_set_data( properties, "producers", producers, 0, ( mlt_destructor )mlt_properties_close, NULL );
		mlt_properties_set_data( properties, "stack", stack, 0, ( mlt_destructor )mlt_deque_close, NULL );
		parser->on_start_producer = on_start_producer;
		parser->on_start_track = on_start_track;
		parser->on_end_track = on_end_track;
		parser->on_start_multitrack = on_start_multitrack;
		parser->on_end_multitrack = on_end_multitrack;
		push( parser, 0, 0, 0 );
		mlt_parser_start( parser, MLT_PRODUCER_SERVICE( self ) );
		free( pop( parser ) );
		for ( k = 0; k < mlt_properties_count( producers ); k ++ )
		{
			char *name = mlt_properties_get_name( producers, k );
			int count = 0;
			int clones = 0;
			int max_clones = 0;
			mlt_producer producer = mlt_properties_get_data_at( producers, k, &count );
			if ( producer != NULL && count > 1 )
			{
				clip_references *refs = mlt_properties_get_data( properties, name, &count );
				for ( i = 0; i < count; i ++ )
				{
					clones = 0;
					for ( j = i + 1; j < count; j ++ )
					{
						if ( intersect( &refs[ i ], &refs[ j ] ) )
						{
							clones ++;
							mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( refs[ j ].cut ), "_clone", clones );
						}
					}
					if ( clones > max_clones )
						max_clones = clones;
				}

				for ( i = 0; i < count; i ++ )
				{
					mlt_producer cut = refs[ i ].cut;
					if ( mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( cut ), "_clone" ) == -1 )
						mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( cut ), "_clone", 0 );
				}

				mlt_producer_set_clones( producer, max_clones );
			}
			else if ( producer != NULL )
			{
				clip_references *refs = mlt_properties_get_data( properties, name, &count );
				for ( i = 0; i < count; i ++ )
				{
					mlt_producer cut = refs[ i ].cut;
					mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( cut ), "_clone", 0 );
				}
				mlt_producer_set_clones( producer, 0 );
			}
		}
		mlt_parser_close( parser );
	}
	return error;
}
Beispiel #18
0
static int producer_get_frame( mlt_service service, mlt_frame_ptr frame, int index )
{
	int result = 1;
	mlt_producer self = service != NULL ? service->child : NULL;

	if ( self != NULL && !mlt_producer_is_cut( self ) )
	{
		// Get the properties of this producer
		mlt_properties properties = MLT_PRODUCER_PROPERTIES( self );

		// Determine eof handling
		char *eof = mlt_properties_get( MLT_PRODUCER_PROPERTIES( self ), "eof" );

		// Get the speed of the producer
		double speed = mlt_producer_get_speed( self );

		// We need to use the clone if it's specified
		mlt_producer clone = mlt_properties_get_data( properties, "use_clone", NULL );

		// If no clone is specified, use self
		clone = clone == NULL ? self : clone;

		// A properly instatiated producer will have a get_frame method...
		if ( self->get_frame == NULL || ( eof && !strcmp( eof, "continue" ) && mlt_producer_position( self ) > mlt_producer_get_out( self ) ) )
		{
			// Generate a test frame
			*frame = mlt_frame_init( service );

			// Set the position
			result = mlt_frame_set_position( *frame, mlt_producer_position( self ) );

			// Mark as a test card
			mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "test_image", 1 );
			mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "test_audio", 1 );

			// Calculate the next position
			mlt_producer_prepare_next( self );
		}
		else
		{
			// Get the frame from the implementation
			result = self->get_frame( clone, frame, index );
		}

		// Copy the fps and speed of the producer onto the frame
		properties = MLT_FRAME_PROPERTIES( *frame );
		mlt_properties_set_double( properties, "_speed", speed );
		mlt_properties_set_int( properties, "test_audio", mlt_frame_is_test_audio( *frame ) );
		mlt_properties_set_int( properties, "test_image", mlt_frame_is_test_card( *frame ) );
		if ( mlt_properties_get_data( properties, "_producer", NULL ) == NULL )
			mlt_properties_set_data( properties, "_producer", service, 0, NULL, NULL );
	}
	else if ( self != NULL )
	{
		// Get the speed of the cut
		double speed = mlt_producer_get_speed( self );

		// Get the parent of the cut
		mlt_producer parent = mlt_producer_cut_parent( self );

		// Get the properties of the parent
		mlt_properties parent_properties = MLT_PRODUCER_PROPERTIES( parent );

		// Get the properties of the cut
		mlt_properties properties = MLT_PRODUCER_PROPERTIES( self );

		// Determine the clone index
		int clone_index = mlt_properties_get_int( properties, "_clone" );

		// Determine the clone to use
		mlt_producer clone = self;

		if ( clone_index > 0 )
		{
			char key[ 25 ];
			sprintf( key, "_clone.%d", clone_index - 1 );
			clone = mlt_properties_get_data( MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( self ) ), key, NULL );
			if ( clone == NULL ) mlt_log( service, MLT_LOG_ERROR, "requested clone doesn't exist %d\n", clone_index );
			clone = clone == NULL ? self : clone;
		}
		else
		{
			clone = parent;
		}

		// We need to seek to the correct position in the clone
		mlt_producer_seek( clone, mlt_producer_get_in( self ) + mlt_properties_get_int( properties, "_position" ) );

		// Assign the clone property to the parent
		mlt_properties_set_data( parent_properties, "use_clone", clone, 0, NULL, NULL );

		// Now get the frame from the parents service
		result = mlt_service_get_frame( MLT_PRODUCER_SERVICE( parent ), frame, index );

		// We're done with the clone now
		mlt_properties_set_data( parent_properties, "use_clone", NULL, 0, NULL, NULL );

		// This is useful and required by always_active transitions to determine in/out points of the cut
		if ( mlt_properties_get_data( MLT_FRAME_PROPERTIES( *frame ), "_producer", NULL ) == MLT_PRODUCER_SERVICE( parent ) )
			mlt_properties_set_data( MLT_FRAME_PROPERTIES( *frame ), "_producer", self, 0, NULL, NULL );

		mlt_properties_set_double( MLT_FRAME_PROPERTIES( *frame ), "_speed", speed );
		mlt_producer_prepare_next( self );
	}
	else
	{
		*frame = mlt_frame_init( service );
		result = 0;
	}

	// Pass on all meta properties from the producer/cut on to the frame
	if ( *frame != NULL && self != NULL )
	{
		int i = 0;
		mlt_properties p_props = MLT_PRODUCER_PROPERTIES( self );
		mlt_properties f_props = MLT_FRAME_PROPERTIES( *frame );
		mlt_properties_lock( p_props );
		int count = mlt_properties_count( p_props );
		for ( i = 0; i < count; i ++ )
		{
			char *name = mlt_properties_get_name( p_props, i );
			if ( !strncmp( name, "meta.", 5 ) )
				mlt_properties_set( f_props, name, mlt_properties_get_value( p_props, i ) );
			else if ( !strncmp( name, "set.", 4 ) )
				mlt_properties_set( f_props, name + 4, mlt_properties_get_value( p_props, i ) );
		}
		mlt_properties_unlock( p_props );
	}

	return result;
}
Beispiel #19
0
mlt_producer producer_pango_init( const char *filename )
{
	producer_pango this = calloc( sizeof( struct producer_pango_s ), 1 );
	if ( this != NULL && mlt_producer_init( &this->parent, this ) == 0 )
	{
		mlt_producer producer = &this->parent;

		pthread_mutex_lock( &pango_mutex );
		if ( fontmap == NULL )
			fontmap = (PangoFT2FontMap*) pango_ft2_font_map_new();
		g_type_init();
		pthread_mutex_unlock( &pango_mutex );

		producer->get_frame = producer_get_frame;
		producer->close = ( mlt_destructor )producer_close;

		// Get the properties interface
		mlt_properties properties = MLT_PRODUCER_PROPERTIES( &this->parent );

		// Set the default properties
		mlt_properties_set( properties, "fgcolour", "0xffffffff" );
		mlt_properties_set( properties, "bgcolour", "0x00000000" );
		mlt_properties_set( properties, "olcolour", "0x00000000" );
		mlt_properties_set_int( properties, "align", pango_align_left );
		mlt_properties_set_int( properties, "pad", 0 );
		mlt_properties_set_int( properties, "outline", 0 );
		mlt_properties_set( properties, "text", "" );
		mlt_properties_set( properties, "font", NULL );
		mlt_properties_set( properties, "family", "Sans" );
		mlt_properties_set_int( properties, "size", 48 );
		mlt_properties_set( properties, "style", "normal" );
		mlt_properties_set( properties, "encoding", "UTF-8" );
		mlt_properties_set_int( properties, "weight", PANGO_WEIGHT_NORMAL );
		mlt_properties_set_int( properties, "seekable", 1 );

		if ( filename == NULL || ( filename && ( !strcmp( filename, "" )
			// workaround for old kdenlive countdown generator
			|| strstr( filename, "&lt;producer&gt;" ) ) ) )
		{
			mlt_properties_set( properties, "markup", "" );
		}
		else if ( filename[ 0 ] == '+' || strstr( filename, "/+" ) )
		{
			char *copy = strdup( filename + 1 );
			char *markup = copy;
			if ( strstr( markup, "/+" ) )
				markup = strstr( markup, "/+" ) + 2;
			( *strrchr( markup, '.' ) ) = '\0';
			while ( strchr( markup, '~' ) )
				( *strchr( markup, '~' ) ) = '\n';
			mlt_properties_set( properties, "resource", filename );
			mlt_properties_set( properties, "markup", markup );
			free( copy );
		}
		else if ( strstr( filename, ".mpl" ) ) 
		{
			int i = 0;
			mlt_properties contents = mlt_properties_load( filename );
			mlt_geometry key_frames = mlt_geometry_init( );
			struct mlt_geometry_item_s item;
			mlt_properties_set( properties, "resource", filename );
			mlt_properties_set_data( properties, "contents", contents, 0, ( mlt_destructor )mlt_properties_close, NULL );
			mlt_properties_set_data( properties, "key_frames", key_frames, 0, ( mlt_destructor )mlt_geometry_close, NULL );

			// Make sure we have at least one entry
			if ( mlt_properties_get( contents, "0" ) == NULL )
				mlt_properties_set( contents, "0", "" );

			for ( i = 0; i < mlt_properties_count( contents ); i ++ )
			{
				char *name = mlt_properties_get_name( contents, i );
				char *value = mlt_properties_get_value( contents, i );
				while ( value != NULL && strchr( value, '~' ) )
					( *strchr( value, '~' ) ) = '\n';
				item.frame = atoi( name );
				mlt_geometry_insert( key_frames, &item );
			}
			mlt_geometry_interpolate( key_frames );
		}
		else
		{
			FILE *f = fopen( filename, "r" );
			if ( f != NULL )
			{
				char line[81];
				char *markup = NULL;
				size_t size = 0;
				line[80] = '\0';
				
				while ( fgets( line, 80, f ) )
				{
					size += strlen( line ) + 1;
					if ( markup )
					{
						markup = realloc( markup, size );
						strcat( markup, line );
					}
					else
					{
						markup = strdup( line );
					}
				}
				fclose( f );

				if ( markup[ strlen( markup ) - 1 ] == '\n' ) 
					markup[ strlen( markup ) - 1 ] = '\0';

				mlt_properties_set( properties, "resource", filename );
				mlt_properties_set( properties, "markup", ( markup == NULL ? "" : markup ) );
				free( markup );
			}
			else
			{
				producer->close = NULL;
				mlt_producer_close( producer );
				producer = NULL;
				free( this );
			}
		}

		return producer;
	}
	free( this );
	return NULL;
}
Beispiel #20
0
static void foreach_consumer_init( mlt_consumer consumer )
{
    const char *resource = mlt_properties_get( MLT_CONSUMER_PROPERTIES(consumer), "resource" );
    mlt_properties properties = mlt_properties_parse_yaml( resource );
    char key[20];
    int index = 0;

    if ( mlt_properties_get_data( MLT_CONSUMER_PROPERTIES(consumer), "0", NULL ) )
    {
        // Properties set directly by application
        mlt_properties p;

        if ( properties )
            mlt_properties_close( properties );
        properties = MLT_CONSUMER_PROPERTIES(consumer);
        do {
            snprintf( key, sizeof(key), "%d", index );
            if ( ( p = mlt_properties_get_data( properties, key, NULL ) ) )
                generate_consumer( consumer, p, index++ );
        } while ( p );
    }
    else if ( properties && mlt_properties_get_data( properties, "0", NULL ) )
    {
        // YAML file supplied
        mlt_properties p;

        do {
            snprintf( key, sizeof(key), "%d", index );
            if ( ( p = mlt_properties_get_data( properties, key, NULL ) ) )
                generate_consumer( consumer, p, index++ );
        } while ( p );
        mlt_properties_close( properties );
    }
    else
    {
        // properties file supplied or properties on this consumer
        const char *s;

        if ( properties )
            mlt_properties_close( properties );
        if ( resource )
            properties = mlt_properties_load( resource );
        else
            properties = MLT_CONSUMER_PROPERTIES( consumer );

        do {
            snprintf( key, sizeof(key), "%d", index );
            if ( ( s = mlt_properties_get( properties, key ) ) )
            {
                mlt_properties p = mlt_properties_new();
                int i, count;

                if ( !p ) break;
                mlt_properties_set( p, "mlt_service", mlt_properties_get( properties, key ) );
                snprintf( key, sizeof(key), "%d.", index );

                count = mlt_properties_count( properties );
                for ( i = 0; i < count; i++ )
                {
                    char *name = mlt_properties_get_name( properties, i );
                    if ( !strncmp( name, key, strlen(key) ) )
                        mlt_properties_set( p, name + strlen(key),
                                            mlt_properties_get_value( properties, i ) );
                }
                generate_consumer( consumer, p, index++ );
                mlt_properties_close( p );
            }
        } while ( s );
        if ( resource )
            mlt_properties_close( properties );
    }
}
void TransitionHandler::updateTransitionParams(QString type, int a_track, int b_track, GenTime in, GenTime out, QDomElement xml)
{
    QScopedPointer<Mlt::Field> field(m_tractor->field());
    field->lock();

    mlt_service nextservice = mlt_service_get_producer(field->get_service());
    mlt_properties properties = MLT_SERVICE_PROPERTIES(nextservice);
    QString mlt_type = mlt_properties_get(properties, "mlt_type");
    QString resource = mlt_properties_get(properties, "mlt_service");
    int in_pos = (int) in.frames(m_fps);
    int out_pos = (int) out.frames(m_fps) - 1;

    while (mlt_type == QLatin1String("transition")) {
        mlt_transition tr = (mlt_transition) nextservice;
        int currentTrack = mlt_transition_get_b_track(tr);
        int currentBTrack = mlt_transition_get_a_track(tr);
        int currentIn = (int) mlt_transition_get_in(tr);
        int currentOut = (int) mlt_transition_get_out(tr);

        // //qDebug()<<"Looking for transition : " << currentIn <<'x'<<currentOut<< ", OLD oNE: "<<in_pos<<'x'<<out_pos;
        if (resource == type && b_track == currentTrack && currentIn == in_pos && currentOut == out_pos) {
            QMap<QString, QString> map = getTransitionParamsFromXml(xml);
            QMap<QString, QString>::Iterator it;
            QString key;
            mlt_properties transproperties = MLT_TRANSITION_PROPERTIES(tr);

            QString currentId = mlt_properties_get(transproperties, "kdenlive_id");
            if (currentId != xml.attribute(QStringLiteral("id"))) {
                // The transition ID is not the same, so reset all properties
                mlt_properties_set(transproperties, "kdenlive_id", xml.attribute(QStringLiteral("id")).toUtf8().constData());
                // Cleanup previous properties
                QStringList permanentProps;
                permanentProps << QStringLiteral("factory") << QStringLiteral("kdenlive_id") << QStringLiteral("mlt_service") << QStringLiteral("mlt_type") << QStringLiteral("in");
                permanentProps << QStringLiteral("out") << QStringLiteral("a_track") << QStringLiteral("b_track");
                for (int i = 0; i < mlt_properties_count(transproperties); ++i) {
                    QString propName = mlt_properties_get_name(transproperties, i);
                    if (!propName.startsWith('_') && ! permanentProps.contains(propName)) {
                        mlt_properties_set(transproperties, propName.toUtf8().constData(), "");
                    }
                }
            }

            mlt_properties_set_int(transproperties, "force_track", xml.attribute(QStringLiteral("force_track")).toInt());
            mlt_properties_set_int(transproperties, "automatic", xml.attribute(QStringLiteral("automatic"), QStringLiteral("0")).toInt());

            if (currentBTrack != a_track) {
                mlt_properties_set_int(transproperties, "a_track", a_track);
            }
            for (it = map.begin(); it != map.end(); ++it) {
                key = it.key();
                mlt_properties_set(transproperties, key.toUtf8().constData(), it.value().toUtf8().constData());
                ////qDebug() << " ------  UPDATING TRANS PARAM: " << key.toUtf8().constData() << ": " << it.value().toUtf8().constData();
                //filter->set("kdenlive_id", id);
            }
            break;
        }
        nextservice = mlt_service_producer(nextservice);
        if (nextservice == NULL) break;
        properties = MLT_SERVICE_PROPERTIES(nextservice);
        mlt_type = mlt_properties_get(properties, "mlt_type");
        resource = mlt_properties_get(properties, "mlt_service");
    }
    field->unlock();
    //askForRefresh();
    //if (m_isBlocked == 0) m_mltConsumer->set("refresh", 1);
}
Beispiel #22
0
static int transition_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{
	// Error we will return
	int error = 0;

	// We will get the 'b frame' from the frame stack
	mlt_frame b_frame = mlt_frame_pop_frame( frame );

	// Get the watermark transition object
	mlt_transition transition = mlt_frame_pop_service( frame );

	// Get the properties of the transitionfin
	mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition );

	// Get the properties of the a frame
	mlt_properties a_props = MLT_FRAME_PROPERTIES( frame );

	mlt_service_lock( MLT_TRANSITION_SERVICE( transition ) );

	// Get the composite from the transition
	mlt_transition composite = mlt_properties_get_data( properties, "composite", NULL );

	// Look for the first filter
	mlt_filter filter = mlt_properties_get_data( properties, "_filter_0", NULL );

	// Get the position
	mlt_position position = mlt_transition_get_position( transition, frame );

	// Create a composite if we don't have one
	if ( composite == NULL )
	{
		// Create composite via the factory
		mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( transition ) );
		composite = mlt_factory_transition( profile, "composite", NULL );

		// If we have one
		if ( composite != NULL )
		{
			// Get the properties
			mlt_properties composite_properties = MLT_TRANSITION_PROPERTIES( composite );

			// We want to ensure that we don't get a wobble...
			//mlt_properties_set_int( composite_properties, "distort", 1 );
			mlt_properties_set_int( composite_properties, "progressive", 1 );

			// Pass all the composite. properties on the transition down
			mlt_properties_pass( composite_properties, properties, "composite." );

			// Register the composite for reuse/destruction
			mlt_properties_set_data( properties, "composite", composite, 0, ( mlt_destructor )mlt_transition_close, NULL );
		}
	}
	else
	{
		// Pass all current properties down
		mlt_properties composite_properties = MLT_TRANSITION_PROPERTIES( composite );
		mlt_properties_pass( composite_properties, properties, "composite." );
	}

	// Create filters
	if ( filter == NULL )
	{
		// Loop Variable
		int i = 0;

		// Number of filters created
		int count = 0;

		// Loop for all properties
		for ( i = 0; i < mlt_properties_count( properties ); i ++ )
		{
			// Get the name of this property
			char *name = mlt_properties_get_name( properties, i );

			// If the name does not contain a . and matches filter
			if ( strchr( name, '.' ) == NULL && !strncmp( name, "filter", 6 ) )
			{
				// Get the filter constructor
				char *value = mlt_properties_get_value( properties, i );

				// Create an instance
				if ( create_instance( transition, name, value, count ) == 0 )
					count ++;
			}
		}
	
		// Look for the first filter again
		filter = mlt_properties_get_data( properties, "_filter_0", NULL );
	}
	else
	{
		// Pass all properties down
		mlt_filter temp = NULL;

		// Loop Variable
		int i = 0;

		// Number of filters found
		int count = 0;

		// Loop for all properties
		for ( i = 0; i < mlt_properties_count( properties ); i ++ )
		{
			// Get the name of this property
			char *name = mlt_properties_get_name( properties, i );

			// If the name does not contain a . and matches filter
			if ( strchr( name, '.' ) == NULL && !strncmp( name, "filter", 6 ) )
			{
				// Strings to hold the id and pass down key
				char id[ 256 ];
				char key[ 256 ];

				// Construct id and key
				sprintf( id, "_filter_%d", count );
				sprintf( key, "%s.", name );

				// Get the filter
				temp = mlt_properties_get_data( properties, id, NULL );

				if ( temp != NULL )
				{
					mlt_properties_pass( MLT_FILTER_PROPERTIES( temp ), properties, key );
					count ++;
				}
			}
		}
	}

	mlt_properties_set_int( a_props, "width", *width );
	mlt_properties_set_int( a_props, "height", *height );

	// Only continue if we have both filter and composite
	if ( composite != NULL )
	{
		// Get the resource of this filter (could be a shape [rectangle/circle] or an alpha provider of choice
		const char *resource =  mlt_properties_get( properties, "resource" );

		// Get the old resource in case it's changed
		char *old_resource =  mlt_properties_get( properties, "_old_resource" );

		// String to hold the filter to query on
		char id[ 256 ];

		// Index to hold the count
		int i = 0;

		// We will get the 'b frame' from the composite only if it's NULL (region filter)
		if ( b_frame == NULL )
		{
			// Copy the region
			b_frame = composite_copy_region( composite, frame, position );

			// Ensure a destructor
			char *name = mlt_properties_get( properties, "_unique_id" );
			mlt_properties_set_data( a_props, name, b_frame, 0, ( mlt_destructor )mlt_frame_close, NULL );
		}

		// Properties of the B framr
		mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame );

		// filter_only prevents copying the alpha channel of the shape to the output frame
		// by compositing filtered frame over itself
		if ( mlt_properties_get_int( properties, "filter_only" ) )
		{
			char *name = mlt_properties_get( properties, "_unique_id" );
			frame = composite_copy_region( composite, b_frame, position );
			mlt_properties_set_data( b_props, name, frame, 0, ( mlt_destructor )mlt_frame_close, NULL );
		}

		// Make sure the filter is in the correct position
		while ( filter != NULL )
		{
			// Stack this filter
			if ( mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "off" ) == 0 )
				mlt_filter_process( filter, b_frame );

			// Generate the key for the next
			sprintf( id, "_filter_%d", ++ i );

			// Get the next filter
			filter = mlt_properties_get_data( properties, id, NULL );
		}

		// Allow filters to be attached to a region filter
		filter = mlt_properties_get_data( properties, "_region_filter", NULL );
		if ( filter != NULL )
			mlt_service_apply_filters( MLT_FILTER_SERVICE( filter ), b_frame, 0 );

		// Hmm - this is probably going to go wrong....
		mlt_frame_set_position( frame, position );

		// Get the b frame and process with composite if successful
		mlt_transition_process( composite, frame, b_frame );

		// If we have a shape producer copy the alpha mask from the shape frame to the b_frame
		if ( strcmp( resource, "rectangle" ) != 0 )
		{
			// Get the producer from the transition
			mlt_producer producer = mlt_properties_get_data( properties, "producer", NULL );

			// If We have no producer then create one
			if ( producer == NULL || ( old_resource != NULL && strcmp( resource, old_resource ) ) )
			{
				// Get the factory producer service
				char *factory = mlt_properties_get( properties, "factory" );

				// Store the old resource
				mlt_properties_set( properties, "_old_resource", resource );

				// Special case circle resource
				if ( strcmp( resource, "circle" ) == 0 )
					resource = "pixbuf:<svg width='100' height='100'><circle cx='50' cy='50' r='50' fill='black'/></svg>";

				// Create the producer
				mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( transition ) );
				producer = mlt_factory_producer( profile, factory, resource );

				// If we have one
				if ( producer != NULL )
				{
					// Get the producer properties
					mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer );

					// Ensure that we loop
					mlt_properties_set( producer_properties, "eof", "loop" );

					// Now pass all producer. properties on the transition down
					mlt_properties_pass( producer_properties, properties, "producer." );

					// Register the producer for reuse/destruction
					mlt_properties_set_data( properties, "producer", producer, 0, ( mlt_destructor )mlt_producer_close, NULL );
				}
			}

			// Now use the shape producer
			if ( producer != NULL )
			{
				// We will get the alpha frame from the producer
				mlt_frame shape_frame = NULL;

				// Make sure the producer is in the correct position
				mlt_producer_seek( producer, position );

				// Get the shape frame
				if ( mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &shape_frame, 0 ) == 0 )
				{
					// Ensure that the shape frame will be closed
					mlt_properties_set_data( b_props, "shape_frame", shape_frame, 0, ( mlt_destructor )mlt_frame_close, NULL );
					if ( mlt_properties_get_int(properties, "holecolor") ) {
						mlt_properties_set_int(b_props, "holecolor", mlt_properties_get_int(properties,"holecolor"));
					}

					// Specify the callback for evaluation
					b_frame->get_alpha_mask = filter_get_alpha_mask;
				}
			}
		}

		// Get the image
		error = mlt_frame_get_image( frame, image, format, width, height, 0 );
	}

	mlt_service_unlock( MLT_TRANSITION_SERVICE( transition ) );

	return error;
}
Beispiel #23
0
static mlt_producer create_producer( mlt_profile profile, char *file )
{
	mlt_producer result = NULL;

	// 1st 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( profile, service, resource );
		free( temp );
	}

	// 2nd Line preferences
	if ( result == NULL )
	{
		int i = 0;
		char *lookup = strdup( file );
		char *p = lookup;

		// Make backup of profile for determining if we need to use 'consumer' producer.
		mlt_profile backup_profile = mlt_profile_clone( profile );

		// We only need to load the dictionary once
		if ( dictionary == NULL )
		{
			char temp[ 1024 ];
			sprintf( temp, "%s/core/loader.dict", mlt_environment( "MLT_DATA" ) );
			dictionary = mlt_properties_load( temp );
			mlt_factory_register_for_clean_up( dictionary, ( mlt_destructor )mlt_properties_close );
		}

		// Convert the lookup string to lower case
		while ( *p )
		{
			*p = tolower( *p );
			p ++;
		}

		// Iterate through the dictionary
		for ( i = 0; result == NULL && i < mlt_properties_count( dictionary ); i ++ )
		{
			char *name = mlt_properties_get_name( dictionary, i );
			if ( fnmatch( name, lookup, 0 ) == 0 )
				result = create_from( profile, file, mlt_properties_get_value( dictionary, i ) );
		}	

		// Check if the producer changed the profile - xml does this.
		// The consumer producer does not handle frame rate differences.
		if ( result && backup_profile->is_explicit && (
		     profile->width != backup_profile->width ||
		     profile->height != backup_profile->height ||
		     profile->sample_aspect_num != backup_profile->sample_aspect_num ||
		     profile->sample_aspect_den != backup_profile->sample_aspect_den ||
		     profile->colorspace != backup_profile->colorspace ) )
		{
			// Restore the original profile attributes.
			profile->display_aspect_den = backup_profile->display_aspect_den;
			profile->display_aspect_num = backup_profile->display_aspect_num;
			profile->frame_rate_den = backup_profile->frame_rate_den;
			profile->frame_rate_num = backup_profile->frame_rate_num;
			profile->height = backup_profile->height;
			profile->progressive = backup_profile->progressive;
			profile->sample_aspect_den = backup_profile->sample_aspect_den;
			profile->sample_aspect_num = backup_profile->sample_aspect_num;
			profile->width = backup_profile->width;

			// Use the 'consumer' producer.
			mlt_producer_close( result );
			result = mlt_factory_producer( profile, "consumer", file );
		}

		mlt_profile_close( backup_profile );
		free( lookup );
	}

	// Finally, try just loading as service
	if ( result == NULL )
		result = mlt_factory_producer( profile, file, NULL );

	return result;
}
Beispiel #24
0
static int process_feed( mlt_properties feed, mlt_filter filter, mlt_frame frame )
{
	// Error return
	int error = 1;

	// Get the properties of the data show filter
	mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter );

	// Get the type requested by the feeding filter
	char *type = mlt_properties_get( feed, "type" );

	// Fetch the filter associated to this type
	mlt_filter requested = mlt_properties_get_data( filter_properties, type, NULL );

	// If it doesn't exist, then create it now
	if ( requested == NULL )
	{
		// Source filter from profile
		requested = obtain_filter( filter, type );

		// Store it on the properties for subsequent retrieval/destruction
		mlt_properties_set_data( filter_properties, type, requested, 0, ( mlt_destructor )mlt_filter_close, NULL );
	}

	// If we have one, then process it now...
	if ( requested != NULL )
	{
		int i = 0;
		mlt_properties properties = MLT_FILTER_PROPERTIES( requested );
		static const char *prefix = "properties.";
		int len = strlen( prefix );

		// Determine if this is an absolute or relative feed
		int absolute = mlt_properties_get_int( feed, "absolute" );

		// Make do with what we have
		int length = !absolute ? 
					 mlt_properties_get_int( feed, "out" ) - mlt_properties_get_int( feed, "in" ) + 1 :
					 mlt_properties_get_int( feed, "out" ) + 1;

		// Repeat period
		int period = mlt_properties_get_int( properties, "period" );
		period = period == 0 ? 1 : period;

		// Pass properties from feed into requested
		for ( i = 0; i < mlt_properties_count( properties ); i ++ )
		{
			char *name = mlt_properties_get_name( properties, i );
			char *key = mlt_properties_get_value( properties, i );
			if ( !strncmp( name, prefix, len ) )
			{
				if ( !strncmp( name + len, "length[", 7 ) )
				{
					mlt_properties_set_position( properties, key, ( length - period ) / period );
				}
				else
				{
					char *value = mlt_properties_get( feed, name + len );
					if ( value != NULL )
					{
						// check for metadata keywords in metadata markup if user requested so
						if ( mlt_properties_get_int( filter_properties, "dynamic" ) == 1  && !strcmp( name + strlen( name ) - 6, "markup") )
						{
							// Find keywords which should be surrounded by '#', like: #title#
							char* keywords = strtok( value, "#" );
							char result[512] = ""; // XXX: how much is enough?
							int ct = 0;
							int fromStart = ( value[0] == '#' ) ? 1 : 0;
							
							while ( keywords != NULL )
							{
								if ( ct % 2 == fromStart )
								{
									// backslash in front of # suppresses substitution
									if ( keywords[ strlen( keywords ) -1 ] == '\\' )
									{
										// keep characters except backslash
										strncat( result, keywords, sizeof( result ) - strlen( result ) - 2 );
										strcat( result, "#" );
										ct++;
									}
									else
									{
										strncat( result, keywords, sizeof( result ) - strlen( result ) - 1 );
									}
								}
								else if ( !strcmp( keywords, "timecode" ) )
								{
									// special case: replace #timecode# with current frame timecode
									mlt_position frames = mlt_properties_get_position( feed, "position" );
									mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
									char *s = mlt_properties_frames_to_time( properties, frames, mlt_time_smpte_df );
									if ( s )
										strncat( result, s, sizeof( result ) - strlen( result ) - 1 );
								}
								else if ( !strcmp( keywords, "frame" ) )
								{
									// special case: replace #frame# with current frame number
									int pos = mlt_properties_get_int( feed, "position" );
									char s[12];
									snprintf( s, sizeof(s) - 1, "%d", pos );
									s[sizeof( s ) - 1] = '\0';
									strncat( result, s, sizeof( result ) - strlen( result ) - 1 );
								}
								else
								{
									// replace keyword with metadata value
									char *metavalue = metadata_value( MLT_FRAME_PROPERTIES( frame ), keywords );
									strncat( result, metavalue ? metavalue : "-", sizeof( result ) - strlen( result ) -1 );
								}
								keywords = strtok( NULL, "#" );
								ct++;
							}
							mlt_properties_set( properties, key, (char*) result );
						}
						else mlt_properties_set( properties, key, value );
					}
				}
			}
		}

		// Set the original position on the frame
		if ( absolute == 0 )
			mlt_frame_set_position( frame, mlt_properties_get_int( feed, "position" ) - mlt_properties_get_int( feed, "in" ) );
		else
			mlt_frame_set_position( frame, mlt_properties_get_int( feed, "position" ) );

		// Process the filter
		mlt_filter_process( requested, frame );

		// Should be ok...
		error = 0;
	}

	return error;
}
Beispiel #25
0
void mlt_factory_register_for_clean_up( void *ptr, mlt_destructor destructor )
{
	char unique[ 256 ];
	sprintf( unique, "%08d", mlt_properties_count( global_properties ) );
	mlt_properties_set_data( global_properties, unique, ptr, 0, destructor, NULL );
}
Beispiel #26
0
static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int track )
{
	mlt_tractor self = parent->child;

	// We only respond to the first track requests
	if ( track == 0 && self->producer != NULL )
	{
		int i = 0;
		int done = 0;
		mlt_frame temp = NULL;
		int count = 0;
		int image_count = 0;

		// Get the properties of the parent producer
		mlt_properties properties = MLT_PRODUCER_PROPERTIES( parent );

		// Try to obtain the multitrack associated to the tractor
		mlt_multitrack multitrack = mlt_properties_get_data( properties, "multitrack", NULL );

		// Or a specific producer
		mlt_producer producer = mlt_properties_get_data( properties, "producer", NULL );

		// Determine whether this tractor feeds to the consumer or stops here
		int global_feed = mlt_properties_get_int( properties, "global_feed" );

		// If we don't have one, we're in trouble...
		if ( multitrack != NULL )
		{
			// The output frame will hold the 'global' data feeds (ie: those which are targetted for the final frame)
			mlt_deque data_queue = mlt_deque_init( );

			// Used to garbage collect all frames
			char label[ 30 ];

			// Get the id of the tractor
			char *id = mlt_properties_get( properties, "_unique_id" );

			// Will be used to store the frame properties object
			mlt_properties frame_properties = NULL;

			// We'll store audio and video frames to use here
			mlt_frame audio = NULL;
			mlt_frame video = NULL;
			mlt_frame first_video = NULL;

			// Temporary properties
			mlt_properties temp_properties = NULL;

			// Get the multitrack's producer
			mlt_producer target = MLT_MULTITRACK_PRODUCER( multitrack );
			mlt_producer_seek( target, mlt_producer_frame( parent ) );
			mlt_producer_set_speed( target, mlt_producer_get_speed( parent ) );

			// We will create one frame and attach everything to it
			*frame = mlt_frame_init( MLT_PRODUCER_SERVICE( parent ) );

			// Get the properties of the frame
			frame_properties = MLT_FRAME_PROPERTIES( *frame );

			// Loop through each of the tracks we're harvesting
			for ( i = 0; !done; i ++ )
			{
				// Get a frame from the producer
				mlt_service_get_frame( self->producer, &temp, i );

				// Get the temporary properties
				temp_properties = MLT_FRAME_PROPERTIES( temp );

				// Pass all unique meta properties from the producer's frame to the new frame
				mlt_properties_lock( temp_properties );
				int props_count = mlt_properties_count( temp_properties );
				int j;
				for ( j = 0; j < props_count; j ++ )
				{
					char *name = mlt_properties_get_name( temp_properties, j );
					if ( !strncmp( name, "meta.", 5 ) && !mlt_properties_get( frame_properties, name ) )
						mlt_properties_set( frame_properties, name, mlt_properties_get_value( temp_properties, j ) );
				}
				mlt_properties_unlock( temp_properties );

				// Copy the format conversion virtual functions
				if ( ! (*frame)->convert_image && temp->convert_image )
					(*frame)->convert_image = temp->convert_image;
				if ( ! (*frame)->convert_audio && temp->convert_audio )
					(*frame)->convert_audio = temp->convert_audio;

				// Check for last track
				done = mlt_properties_get_int( temp_properties, "last_track" );

				// Handle fx only tracks
				if ( mlt_properties_get_int( temp_properties, "fx_cut" ) )
				{
					int hide = ( video == NULL ? 1 : 0 ) | ( audio == NULL ? 2 : 0 );
					mlt_properties_set_int( temp_properties, "hide", hide );
				}

				// We store all frames with a destructor on the output frame
				sprintf( label, "_%s_%d", id, count ++ );
				mlt_properties_set_data( frame_properties, label, temp, 0, ( mlt_destructor )mlt_frame_close, NULL );

				// We want to append all 'final' feeds to the global queue
				if ( !done && mlt_properties_get_data( temp_properties, "data_queue", NULL ) != NULL )
				{
					// Move the contents of this queue on to the output frames data queue
					mlt_deque sub_queue = mlt_properties_get_data( MLT_FRAME_PROPERTIES( temp ), "data_queue", NULL );
					mlt_deque temp = mlt_deque_init( );
					while ( global_feed && mlt_deque_count( sub_queue ) )
					{
						mlt_properties p = mlt_deque_pop_back( sub_queue );
						if ( mlt_properties_get_int( p, "final" ) )
							mlt_deque_push_back( data_queue, p );
						else
							mlt_deque_push_back( temp, p );
					}
					while( mlt_deque_count( temp ) )
						mlt_deque_push_front( sub_queue, mlt_deque_pop_back( temp ) );
					mlt_deque_close( temp );
				}

				// Now do the same with the global queue but without the conditional behaviour
				if ( mlt_properties_get_data( temp_properties, "global_queue", NULL ) != NULL )
				{
					mlt_deque sub_queue = mlt_properties_get_data( MLT_FRAME_PROPERTIES( temp ), "global_queue", NULL );
					while ( mlt_deque_count( sub_queue ) )
					{
						mlt_properties p = mlt_deque_pop_back( sub_queue );
						mlt_deque_push_back( data_queue, p );
					}
				}

				// Pick up first video and audio frames
				if ( !done && !mlt_frame_is_test_audio( temp ) && !( mlt_properties_get_int( temp_properties, "hide" ) & 2 ) )
				{
					// Order of frame creation is starting to get problematic
					if ( audio != NULL )
					{
						mlt_deque_push_front( MLT_FRAME_AUDIO_STACK( temp ), producer_get_audio );
						mlt_deque_push_front( MLT_FRAME_AUDIO_STACK( temp ), audio );
					}
					audio = temp;
				}
				if ( !done && !mlt_frame_is_test_card( temp ) && !( mlt_properties_get_int( temp_properties, "hide" ) & 1 ) )
				{
					if ( video != NULL )
					{
						mlt_deque_push_front( MLT_FRAME_IMAGE_STACK( temp ), producer_get_image );
						mlt_deque_push_front( MLT_FRAME_IMAGE_STACK( temp ), video );
					}
					video = temp;
					if ( first_video == NULL )
						first_video = temp;

					mlt_properties_set_int( MLT_FRAME_PROPERTIES( temp ), "image_count", ++ image_count );
					image_count = 1;
				}
			}

			// Now stack callbacks
			if ( audio != NULL )
			{
				mlt_frame_push_audio( *frame, audio );
				mlt_frame_push_audio( *frame, producer_get_audio );
			}

			if ( video != NULL )
			{
				mlt_properties video_properties = MLT_FRAME_PROPERTIES( first_video );
				mlt_frame_push_service( *frame, video );
				mlt_frame_push_service( *frame, producer_get_image );
				if ( global_feed )
					mlt_properties_set_data( frame_properties, "data_queue", data_queue, 0, NULL, NULL );
				mlt_properties_set_data( video_properties, "global_queue", data_queue, 0, destroy_data_queue, NULL );
				mlt_properties_set_int( frame_properties, "width", mlt_properties_get_int( video_properties, "width" ) );
				mlt_properties_set_int( frame_properties, "height", mlt_properties_get_int( video_properties, "height" ) );
				mlt_properties_pass_list( frame_properties, video_properties, "meta.media.width, meta.media.height" );
				mlt_properties_set_int( frame_properties, "progressive", mlt_properties_get_int( video_properties, "progressive" ) );
				mlt_properties_set_double( frame_properties, "aspect_ratio", mlt_properties_get_double( video_properties, "aspect_ratio" ) );
				mlt_properties_set_int( frame_properties, "image_count", image_count );
				mlt_properties_set_data( frame_properties, "_producer", mlt_frame_get_original_producer( first_video ), 0, NULL, NULL );
			}
			else
			{
				destroy_data_queue( data_queue );
			}

			mlt_frame_set_position( *frame, mlt_producer_frame( parent ) );
			mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "test_audio", audio == NULL );
			mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "test_image", video == NULL );
		}
		else if ( producer != NULL )
		{
			mlt_producer_seek( producer, mlt_producer_frame( parent ) );
			mlt_producer_set_speed( producer, mlt_producer_get_speed( parent ) );
			mlt_service_get_frame( self->producer, frame, track );
		}
		else
		{
			mlt_log( MLT_PRODUCER_SERVICE( parent ), MLT_LOG_ERROR, "tractor without a multitrack!!\n" );
			mlt_service_get_frame( self->producer, frame, track );
		}

		// Prepare the next frame
		mlt_producer_prepare_next( parent );

		// Indicate our found status
		return 0;
	}
	else
	{
		// Generate a test card
		*frame = mlt_frame_init( MLT_PRODUCER_SERVICE( parent ) );
		return 0;
	}
}
Beispiel #27
0
static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{
	mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame );
	mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
	mlt_position pos = mlt_filter_get_position( filter, frame );
	mlt_position len = mlt_filter_get_length2( filter, frame );
	
	int maxdia = mlt_properties_anim_get_int( properties, "maxdiameter", pos, len );
	int maxcount = mlt_properties_anim_get_int( properties, "maxcount", pos, len );

	*format = mlt_image_yuv422;
	int error = mlt_frame_get_image( frame, image, format, width, height, 1 );

	// Load svg
	char *factory = mlt_properties_get( properties, "factory" );
	char temp[1204] = "";
	sprintf( temp, "%s/oldfilm/", mlt_environment( "MLT_DATA" ) );
	
	mlt_properties direntries = mlt_properties_new();
	mlt_properties_dir_list( direntries, temp,"dust*.svg",1 );
	
	if (!maxcount)
		return 0;

	double position = mlt_filter_get_progress( filter, frame );
	srand( position * 10000 );

	mlt_service_lock( MLT_FILTER_SERVICE( filter ) );

	int im = rand() % maxcount;
	int piccount = mlt_properties_count( direntries );
	while ( im-- && piccount )
	{
		int picnum = rand() % piccount;
		
		int y1 = rand() % *height;
		int x1 = rand() % *width;
		char resource[1024] = "";
		char savename[1024] = "", savename1[1024] = "", cachedy[100];
		int dx = ( *width * maxdia / 100);
		int luma_width, luma_height;
		uint8_t *luma_image = NULL;
		uint8_t *alpha = NULL;
		int updown = rand() % 2;
		int mirror = rand() % 2;
		
		sprintf( resource, "%s", mlt_properties_get_value(direntries,picnum) );
		sprintf( savename, "cache-%d-%d", picnum,dx );
		sprintf( savename1, "cache-alpha-%d-%d", picnum, dx );
		sprintf( cachedy, "cache-dy-%d-%d", picnum,dx );
		
		luma_image = mlt_properties_get_data( properties , savename , NULL );
		alpha = mlt_properties_get_data( properties , savename1 , NULL );
		
		if ( luma_image == NULL || alpha == NULL )
		{
			mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) );
			mlt_producer producer = mlt_factory_producer( profile, factory, resource );
		
			if ( producer != NULL )
			{
				mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer );
				
				mlt_properties_set( producer_properties, "eof", "loop" );
				mlt_frame luma_frame = NULL;
				
				if ( mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &luma_frame, 0 ) == 0 )
				{
					mlt_image_format luma_format = mlt_image_yuv422;
					luma_width = dx;
					luma_height = luma_width * mlt_properties_get_int( MLT_FRAME_PROPERTIES ( luma_frame ) , "height" ) / mlt_properties_get_int( MLT_FRAME_PROPERTIES ( luma_frame ) , "width" );

					mlt_properties_set( MLT_FRAME_PROPERTIES( luma_frame ), "rescale.interp", "best" );// none/nearest/tiles/hyper
					
					mlt_frame_get_image( luma_frame, &luma_image, &luma_format, &luma_width, &luma_height, 0 );
					alpha = mlt_frame_get_alpha_mask (luma_frame );
					
					uint8_t* savealpha = mlt_pool_alloc( luma_width * luma_height );
					uint8_t* savepic = mlt_pool_alloc( luma_width * luma_height * 2);
					
					if ( savealpha && savepic )
					{
						memcpy( savealpha, alpha , luma_width * luma_height );
						memcpy( savepic, luma_image , luma_width * luma_height * 2 );
						
						mlt_properties_set_data( properties, savename, savepic, luma_width * luma_height * 2, mlt_pool_release, NULL );
						mlt_properties_set_data( properties, savename1, savealpha, luma_width * luma_height,  mlt_pool_release, NULL );
						mlt_properties_set_int( properties, cachedy, luma_height );
						
						overlay_image( *image, *width, *height, luma_image, luma_width, luma_height, alpha, x1, y1, updown, mirror );
					}
					else
					{
						if ( savealpha )
							mlt_pool_release( savealpha );
						if ( savepic )
							mlt_pool_release( savepic );
					}
					mlt_frame_close( luma_frame );	
				}
				mlt_producer_close( producer );	
			}
		}
		else 
		{
			overlay_image ( *image, *width, *height, luma_image, dx, mlt_properties_get_int ( properties, cachedy ), alpha, x1, y1, updown, mirror );
		}
	}

	mlt_service_unlock( MLT_FILTER_SERVICE( filter ) );

	if (piccount>0 )
		return 0;
	if ( error == 0 && *image )
	{

		int h = *height;
		int w = *width;
		int im = rand() % maxcount;
		
		while ( im-- )
		{
			int type = im % 2;
			int y1 = rand() % h;
			int x1 = rand() % w;
			int dx = rand() % maxdia;
			int dy = rand() % maxdia;
			int x=0, y=0;
			double v = 0.0;
			for ( x = -dx ; x < dx ; x++ )
			{
				for ( y = -dy ; y < dy ; y++ ) 
				{
					if ( x1 + x < w && x1 + x > 0 && y1 + y < h && y1 + y > 0 ){
						uint8_t *pix = *image + (y+y1) * w * 2 + (x + x1) * 2;

						v=pow((double) x /(double)dx * 5.0, 2.0) + pow((double)y / (double)dy * 5.0, 2.0);
						if (v>10)
							v=10;
						v = 1.0 - ( v / 10.0 );

						switch(type)
						{
							case 0:
								*pix -= (*pix) * v;
								break;
							case 1:
								*pix += ( 255-*pix ) * v;
								break;
						}
					}
				}
			}
		}
	}

	return error;
}
Beispiel #28
0
static void add_parameters( mlt_properties params, void *object, int req_flags, const char *unit, const char *subclass )
{
	const AVOption *opt = NULL;

	// For each AVOption on the AVClass object
#if LIBAVUTIL_VERSION_INT >= ((51<<16)+(12<<8)+0)
	while ( ( opt = av_opt_next( object, opt ) ) )
#else
	while ( ( opt = av_next_option( object, opt ) ) )
#endif
	{
		// If matches flags and not a binary option (not supported by Mlt)
		if ( !( opt->flags & req_flags ) || ( opt->type == AV_OPT_TYPE_BINARY ) )
            continue;

		// Ignore constants (keyword values)
		if ( !unit && opt->type == AV_OPT_TYPE_CONST )
			continue;
		// When processing a groups of options (unit)...
		// ...ignore non-constants
		else if ( unit && opt->type != AV_OPT_TYPE_CONST )
			continue;
		// ...ignore constants not in this group
		else if ( unit && opt->type == AV_OPT_TYPE_CONST && strcmp( unit, opt->unit ) )
			continue;
		// ..add constants to the 'values' sequence
		else if ( unit && opt->type == AV_OPT_TYPE_CONST )
		{
			char key[20];
			snprintf( key, 20, "%d", mlt_properties_count( params ) );
			mlt_properties_set( params, key, opt->name );
			continue;
		}

		// Create a map for this option.
		mlt_properties p = mlt_properties_new();
		char key[20];
		snprintf( key, 20, "%d", mlt_properties_count( params ) );
		// Add the map to the 'parameters' sequence.
		mlt_properties_set_data( params, key, p, 0, (mlt_destructor) mlt_properties_close, NULL );

		// Add the parameter metadata for this AVOption.
		mlt_properties_set( p, "identifier", opt->name );
		if ( opt->help )
		{
			if ( subclass )
			{
				char *s = malloc( strlen( opt->help ) + strlen( subclass ) + 4 );
				strcpy( s, opt->help );
				strcat( s, " (" );
				strcat( s, subclass );
				strcat( s, ")" );
				mlt_properties_set( p, "description", s );
				free( s );
			}
			else
				mlt_properties_set( p, "description", opt->help );
		}

        switch ( opt->type )
		{
		case AV_OPT_TYPE_FLAGS:
			mlt_properties_set( p, "type", "string" );
			mlt_properties_set( p, "format", "flags" );
			break;
		case AV_OPT_TYPE_INT:
			if ( !opt->unit )
			{
				mlt_properties_set( p, "type", "integer" );
				if ( opt->min != INT_MIN )
					mlt_properties_set_int( p, "minimum", (int) opt->min );
				if ( opt->max != INT_MAX )
					mlt_properties_set_int( p, "maximum", (int) opt->max );
#if LIBAVUTIL_VERSION_MAJOR > 50
				mlt_properties_set_int( p, "default", (int) opt->default_val.dbl );
#endif
			}
			else
			{
				mlt_properties_set( p, "type", "string" );
				mlt_properties_set( p, "format", "integer or keyword" );
			}
			break;
		case AV_OPT_TYPE_INT64:
			mlt_properties_set( p, "type", "integer" );
			mlt_properties_set( p, "format", "64-bit" );
			if ( opt->min != INT64_MIN )
				mlt_properties_set_int64( p, "minimum", (int64_t) opt->min );
			if ( opt->max != INT64_MAX )
			mlt_properties_set_int64( p, "maximum", (int64_t) opt->max );
#if LIBAVUTIL_VERSION_MAJOR > 50
			mlt_properties_set_int64( p, "default", (int64_t) opt->default_val.dbl );
#endif
			break;
		case AV_OPT_TYPE_FLOAT:
			mlt_properties_set( p, "type", "float" );
			if ( opt->min != FLT_MIN && opt->min != -340282346638528859811704183484516925440.0 )
				mlt_properties_set_double( p, "minimum", opt->min );
			if ( opt->max != FLT_MAX )
				mlt_properties_set_double( p, "maximum", opt->max );
#if LIBAVUTIL_VERSION_MAJOR > 50
			mlt_properties_set_double( p, "default", opt->default_val.dbl );
#endif
			break;
		case AV_OPT_TYPE_DOUBLE:
			mlt_properties_set( p, "type", "float" );
			mlt_properties_set( p, "format", "double" );
			if ( opt->min != DBL_MIN )
				mlt_properties_set_double( p, "minimum", opt->min );
			if ( opt->max != DBL_MAX )
				mlt_properties_set_double( p, "maximum", opt->max );
#if LIBAVUTIL_VERSION_MAJOR > 50
			mlt_properties_set_double( p, "default", opt->default_val.dbl );
#endif
			break;
		case AV_OPT_TYPE_STRING:
			mlt_properties_set( p, "type", "string" );
#if LIBAVUTIL_VERSION_MAJOR > 50
			mlt_properties_set( p, "default", opt->default_val.str );
#endif
			break;
		case AV_OPT_TYPE_RATIONAL:
			mlt_properties_set( p, "type", "string" );
			mlt_properties_set( p, "format", "numerator:denominator" );
			break;
		case AV_OPT_TYPE_CONST:
		default:
			mlt_properties_set( p, "type", "integer" );
			mlt_properties_set( p, "format", "constant" );
			break;
        }
		// If the option belongs to a group (unit) and is not a constant (keyword value)
		if ( opt->unit && opt->type != AV_OPT_TYPE_CONST )
		{
			// Create a 'values' sequence.
			mlt_properties values = mlt_properties_new();

			// Recurse to add constants in this group to the 'values' sequence.
			add_parameters( values, object, req_flags, opt->unit, NULL );
			if ( mlt_properties_count( values ) )
				mlt_properties_set_data( p, "values", values, 0, (mlt_destructor) mlt_properties_close, NULL );
			else
				mlt_properties_close( values );
		}
	}
}
Beispiel #29
0
static mlt_properties metadata( mlt_service_type type, const char *id, char *data )
{
	char file[ PATH_MAX ];
	if( type == filter_type )
	{
		snprintf( file, PATH_MAX, "%s/jackrack/%s",
			  mlt_environment( "MLT_DATA" ), strncmp( id, "ladspa.", 7 ) ? data : "filter_ladspa.yml" );
	}
	else
	{
		snprintf( file, PATH_MAX, "%s/jackrack/%s",
			  mlt_environment( "MLT_DATA" ), strncmp( id, "ladspa.", 7 ) ? data : "producer_ladspa.yml" );
	}
	mlt_properties result = mlt_properties_parse_yaml( file );

#ifdef GPL
	if ( !strncmp( id, "ladspa.", 7 ) )
	{
		// Annotate the yaml properties with ladspa control port info.
		plugin_desc_t *desc = plugin_mgr_get_any_desc( g_jackrack_plugin_mgr, strtol( id + 7, NULL, 10 ) );

		if ( desc )
		{
			mlt_properties params = mlt_properties_new();
			mlt_properties p;
			char key[20];
			int i;

			mlt_properties_set( result, "identifier", id );
			mlt_properties_set( result, "title", desc->name );
			mlt_properties_set( result, "creator", desc->maker ? desc->maker : "unknown" );
			mlt_properties_set( result, "description", "LADSPA plugin" );
			mlt_properties_set_data( result, "parameters", params, 0, (mlt_destructor) mlt_properties_close, NULL );
			for ( i = 0; i < desc->control_port_count; i++ )
			{
				int j = desc->control_port_indicies[i];
				p = mlt_properties_new();
				snprintf( key, sizeof(key), "%d", mlt_properties_count( params ) );
				mlt_properties_set_data( params, key, p, 0, (mlt_destructor) mlt_properties_close, NULL );
				snprintf( key, sizeof(key), "%d", j );
				mlt_properties_set( p, "identifier", key );
				add_port_to_metadata( p, desc, j );
				mlt_properties_set( p, "mutable", "yes" );
			}
			for ( i = 0; i < desc->status_port_count; i++ )
			{
				int j = desc->status_port_indicies[i];
				p = mlt_properties_new();
				snprintf( key, sizeof(key), "%d", mlt_properties_count( params ) );
				mlt_properties_set_data( params, key, p, 0, (mlt_destructor) mlt_properties_close, NULL );
				snprintf( key, sizeof(key), "%d[*]", j );
				mlt_properties_set( p, "identifier", key );
				add_port_to_metadata( p, desc, j );
				mlt_properties_set( p, "readonly", "yes" );
			}

			p = mlt_properties_new();
			snprintf( key, sizeof(key), "%d", mlt_properties_count( params ) );
			mlt_properties_set_data( params, key, p, 0, (mlt_destructor) mlt_properties_close, NULL );
			mlt_properties_set( p, "identifier", "instances" );
			mlt_properties_set( p, "title", "Instances" );
			mlt_properties_set( p, "description",
								"The number of instances of the plugin that are in use.\n"
								"MLT will create the number of plugins that are required "
								"to support the number of audio channels.\n"
								"Status parameters (readonly) are provided for each instance "
								"and are accessed by specifying the instance number after the "
								"identifier (starting at zero).\n"
								"e.g. 9[0] provides the value of status 9 for the first instance."
								);
			mlt_properties_set( p, "type", "integer" );
			mlt_properties_set( p, "readonly", "yes" );

			if( type == filter_type )
			{
				p = mlt_properties_new();
				snprintf( key, sizeof(key), "%d", mlt_properties_count( params ) );
				mlt_properties_set_data( params, key, p, 0, (mlt_destructor) mlt_properties_close, NULL );
				mlt_properties_set( p, "identifier", "wetness" );
				mlt_properties_set( p, "title", "Wet/Dry" );
				mlt_properties_set( p, "type", "float" );
				mlt_properties_set_double( p, "default", 1 );
				mlt_properties_set_double( p, "minimum", 0 );
				mlt_properties_set_double( p, "maximum", 1 );
				mlt_properties_set( p, "mutable", "yes" );
			}
		}
	}
#endif

	return result;
}