Beispiel #1
0
static int get_image_b( mlt_frame b_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{
	mlt_transition self = mlt_frame_pop_service( b_frame );
	mlt_frame a_frame = mlt_frame_pop_frame( b_frame );
	mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame );
	mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame );

	// Set scaling from A frame if not already provided.
	if ( !mlt_properties_get( b_props, "rescale.interp" ) )
	{
		const char *rescale = mlt_properties_get( a_props, "rescale.interp" );
		if ( !rescale || !strcmp( rescale, "none" ) )
			rescale = "nearest";
		mlt_properties_set( b_props, "rescale.interp", rescale );
	}

	// Ensure sane aspect ratio
	if ( mlt_frame_get_aspect_ratio( b_frame ) == 0.0 )
		mlt_frame_set_aspect_ratio( b_frame, mlt_profile_sar( mlt_service_profile( MLT_TRANSITION_SERVICE(self) ) ) );

	mlt_properties_pass_list( b_props, a_props,
		"consumer_deinterlace, deinterlace_method, consumer_tff" );

	return mlt_frame_get_image( b_frame, image, format, width, height, writable );
}
Beispiel #2
0
mlt_producer producer_consumer_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
{
	mlt_producer self = mlt_producer_new( profile );

	// Encapsulate the real producer
	mlt_profile temp_profile = mlt_profile_clone( profile );
	temp_profile->is_explicit = 0;
	mlt_producer real_producer = mlt_factory_producer( temp_profile, NULL, arg );

	if ( self && real_producer )
	{
		// Override some producer methods
		self->close = ( mlt_destructor )producer_close;
		self->get_frame = get_frame;
		
		// Get the properties of this producer
		mlt_properties properties = MLT_PRODUCER_PROPERTIES( self );
		mlt_properties_set( properties, "resource", arg );
		mlt_properties_pass_list( properties, MLT_PRODUCER_PROPERTIES( real_producer ), "out, length" );

		// Done with the producer - will re-open later when we have the profile property
		mlt_producer_close( real_producer );
	}
	else
	{
		if ( self )
			mlt_producer_close( self );
		if ( real_producer )
			mlt_producer_close( real_producer );

		self = NULL;
	}
	mlt_profile_close( temp_profile );
	return self;
}
Beispiel #3
0
static mlt_consumer generate_consumer( mlt_consumer consumer, mlt_properties props, int index )
{
    mlt_profile profile = NULL;
    if ( mlt_properties_get( props, "mlt_profile" ) )
        profile = mlt_profile_init( mlt_properties_get( props, "mlt_profile" ) );
    if ( !profile )
        profile = mlt_profile_clone( mlt_service_profile( MLT_CONSUMER_SERVICE(consumer) ) );
    mlt_consumer nested = create_consumer( profile, mlt_properties_get( props, "mlt_service" ),
                                           mlt_properties_get( props, "target" ) );

    if ( nested )
    {
        mlt_properties properties = MLT_CONSUMER_PROPERTIES(consumer);
        mlt_properties nested_props = MLT_CONSUMER_PROPERTIES(nested);
        char key[30];

        snprintf( key, sizeof(key), "%d.consumer", index );
        mlt_properties_set_data( properties, key, nested, 0, (mlt_destructor) mlt_consumer_close, NULL );
        snprintf( key, sizeof(key), "%d.profile", index );
        mlt_properties_set_data( properties, key, profile, 0, (mlt_destructor) mlt_profile_close, NULL );

        mlt_properties_set_int( nested_props, "put_mode", 1 );
        mlt_properties_pass_list( nested_props, properties, "terminate_on_pause" );
        mlt_properties_set( props, "consumer", NULL );
        // set mlt_profile before other properties to facilitate presets
        mlt_properties_pass_list( nested_props, props, "mlt_profile" );
        mlt_properties_inherit( nested_props, props );

        attach_normalisers( profile, MLT_CONSUMER_SERVICE(nested) );

        // Relay the first available consumer-frame-show event
        mlt_event event = mlt_properties_get_data( properties, "frame-show-event", NULL );
        if ( !event )
        {
            event = mlt_events_listen( nested_props, properties, "consumer-frame-show", (mlt_listener) on_frame_show );
            mlt_properties_set_data( properties, "frame-show-event", event, 0, /*mlt_event_close*/ NULL, NULL );
        }
    }
    else
    {
        mlt_profile_close( profile );
    }
    return nested;
}
Beispiel #4
0
static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
{
	if ( frame )
	{
		// Construct a new frame
		*frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) );

		// Stack the producer and producer's get image
		mlt_frame_push_service_int( *frame, index );
		mlt_frame_push_service( *frame, producer );
		mlt_frame_push_service( *frame, framebuffer_get_image );

		mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
		mlt_properties frame_properties = MLT_FRAME_PROPERTIES(*frame);

		// Get frame from the real producer
		mlt_frame first_frame = mlt_properties_get_data( properties, "first_frame", NULL );

		if ( first_frame == NULL )
		{
		    // Get the frame to cache from the real producer
		    mlt_producer real_producer = mlt_properties_get_data( properties, "producer", NULL );

		    // Seek the producer to the correct place
		    mlt_producer_seek( real_producer, mlt_producer_position( producer ) );

		    // Get the frame
		    mlt_service_get_frame( MLT_PRODUCER_SERVICE( real_producer ), &first_frame, index );
		    // Cache the frame
		    mlt_properties_set_data( properties, "first_frame", first_frame, 0, ( mlt_destructor )mlt_frame_close, NULL );
		}

		mlt_properties_inherit( frame_properties, MLT_FRAME_PROPERTIES(first_frame) );
		
		double force_aspect_ratio = mlt_properties_get_double( properties, "force_aspect_ratio" );
		if ( force_aspect_ratio <= 0.0 ) force_aspect_ratio = mlt_properties_get_double( properties, "aspect_ratio" );
		mlt_properties_set_double( frame_properties, "aspect_ratio", force_aspect_ratio );
                
		// Give the returned frame temporal identity
		mlt_frame_set_position( *frame, mlt_producer_position( producer ) );

		mlt_properties_set_int( frame_properties, "meta.media.width", mlt_properties_get_int( properties, "width" ) );
		mlt_properties_set_int( frame_properties, "meta.media.height", mlt_properties_get_int( properties, "height" ) );
		mlt_properties_pass_list( frame_properties, properties, "width, height" );
	}

	return 0;
}
Beispiel #5
0
static mlt_frame process(mlt_filter filter, mlt_frame frame)
{
	mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
	mlt_transition transition = mlt_properties_get_data(properties, "instance", NULL);
	char *name = mlt_properties_get(MLT_FILTER_PROPERTIES(filter), "transition");

	if (!name || !strcmp("", name))
		return frame;

	// Create the transition if needed.
	if (!transition
		|| !mlt_properties_get(MLT_FILTER_PROPERTIES(transition), "mlt_service") 
		|| strcmp(name, mlt_properties_get(MLT_FILTER_PROPERTIES(transition), "mlt_service"))) {
		mlt_profile profile = mlt_service_profile(MLT_FILTER_SERVICE(filter));

		transition = mlt_factory_transition(profile, name, NULL);
		mlt_properties_set_data(MLT_FILTER_PROPERTIES(filter), "instance", transition, 0, (mlt_destructor) mlt_transition_close, NULL);
	}

	if (transition) {
		mlt_properties transition_props = MLT_TRANSITION_PROPERTIES(transition);
		int type = mlt_properties_get_int(transition_props, "_transition_type");
		int hide = mlt_properties_get_int(MLT_FRAME_PROPERTIES(frame), "hide");

		mlt_properties_pass_list(transition_props, properties, "in out");
		mlt_properties_pass(transition_props, properties, "transition." );

		// Only if video transition on visible track.
		if ((type & 1) && !mlt_frame_is_test_card(frame) && !(hide & 1)) {
			mlt_frame_push_service_int(frame,
				mlt_image_format_id(mlt_properties_get(properties, "mlt_image_format")));
			mlt_frame_push_service(frame, transition);
			mlt_frame_push_get_image(frame, get_image);
		}
		if (type == 0)
			mlt_properties_debug(transition_props, "unknown transition type", stderr);
	} else {
		mlt_properties_debug(properties, "mask_failed to create transition", stderr );
	}

	return frame;
}
Beispiel #6
0
static int consumer_start( mlt_consumer parent )
{
	consumer_sdl self = parent->child;

	if ( !self->running )
	{
		// properties
		mlt_properties properties = MLT_CONSUMER_PROPERTIES( parent );
		mlt_properties play = MLT_CONSUMER_PROPERTIES( self->play );
		mlt_properties still = MLT_CONSUMER_PROPERTIES( self->still );

		char *window_id = mlt_properties_get( properties, "window_id" );
		char *audio_driver = mlt_properties_get( properties, "audio_driver" );
		char *video_driver = mlt_properties_get( properties, "video_driver" );
		char *audio_device = mlt_properties_get( properties, "audio_device" );
		char *output_display = mlt_properties_get( properties, "output_display" );
		int progressive = mlt_properties_get_int( properties, "progressive" ) | mlt_properties_get_int( properties, "deinterlace" );

		consumer_stop( parent );

		self->running = 1;
		self->joined = 0;
		self->last_speed = 1;

		if ( output_display != NULL )
			setenv( "DISPLAY", output_display, 1 );

		if ( window_id != NULL )
			setenv( "SDL_WINDOWID", window_id, 1 );

		if ( video_driver != NULL )
			setenv( "SDL_VIDEODRIVER", video_driver, 1 );

		if ( audio_driver != NULL )
			setenv( "SDL_AUDIODRIVER", audio_driver, 1 );

		if ( audio_device != NULL )
			setenv( "AUDIODEV", audio_device, 1 );

		pthread_mutex_lock( &mlt_sdl_mutex );
		int ret = SDL_Init( SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE );
		pthread_mutex_unlock( &mlt_sdl_mutex );
		if ( ret < 0 )
		{
			fprintf( stderr, "Failed to initialize SDL: %s\n", SDL_GetError() );
			return -1;
		}

		SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL );
		SDL_EnableUNICODE( 1 );

		// Pass properties down
		mlt_properties_set_data( play, "transport_producer", mlt_properties_get_data( properties, "transport_producer", NULL ), 0, NULL, NULL );
		mlt_properties_set_data( still, "transport_producer", mlt_properties_get_data( properties, "transport_producer", NULL ), 0, NULL, NULL );
		mlt_properties_set_data( play, "transport_callback", mlt_properties_get_data( properties, "transport_callback", NULL ), 0, NULL, NULL );
		mlt_properties_set_data( still, "transport_callback", mlt_properties_get_data( properties, "transport_callback", NULL ), 0, NULL, NULL );

		mlt_properties_set_int( play, "progressive", progressive );
		mlt_properties_set_int( still, "progressive", progressive );

		mlt_properties_pass_list( play, properties,
			"deinterlace_method,resize,rescale,width,height,aspect_ratio,display_ratio,preview_off,preview_format,window_background"
			",top_field_first,volume,real_time,buffer,prefill,audio_off,frequency,drop_max" );
		mlt_properties_pass_list( still, properties,
			"deinterlace_method,resize,rescale,width,height,aspect_ratio,display_ratio,preview_off,preview_format,window_background"
			",top_field_first");

		mlt_properties_pass( play, properties, "play." );
		mlt_properties_pass( still, properties, "still." );

		mlt_properties_set_data( play, "app_lock", mlt_properties_get_data( properties, "app_lock", NULL ), 0, NULL, NULL );
		mlt_properties_set_data( still, "app_lock", mlt_properties_get_data( properties, "app_lock", NULL ), 0, NULL, NULL );
		mlt_properties_set_data( play, "app_unlock", mlt_properties_get_data( properties, "app_unlock", NULL ), 0, NULL, NULL );
		mlt_properties_set_data( still, "app_unlock", mlt_properties_get_data( properties, "app_unlock", NULL ), 0, NULL, NULL );

		mlt_properties_set_int( play, "put_mode", 1 );
		mlt_properties_set_int( still, "put_mode", 1 );
		mlt_properties_set_int( play, "terminate_on_pause", 1 );

		// Start the still producer just to initialise the gui
		mlt_consumer_start( self->still );
		self->active = self->still;

		// Inform child consumers that we control the sdl
		mlt_properties_set_int( play, "sdl_started", 1 );
		mlt_properties_set_int( still, "sdl_started", 1 );

		pthread_create( &self->thread, NULL, consumer_thread, self );
	}

	return 0;
}
Beispiel #7
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 ) );
	mlt_producer_init( producer, 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_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 #8
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 #9
0
static int create_instance( mlt_transition transition, char *name, char *value, int count )
{
	// Return from this function
	int error = 0;

	// Duplicate the value
	char *type = strdup( value );

	// Pointer to filter argument
	char *arg = type == NULL ? NULL : strchr( type, ':' );

	// New filter being created
	mlt_filter filter = NULL;

	// Cleanup type and arg
	if ( arg != NULL )
		*arg ++ = '\0';

	// Create the filter
	mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( transition ) );
	if ( type )
		filter = mlt_factory_filter( profile, type, arg );

	// If we have a filter, then initialise and store it
	if ( filter != NULL )
	{
		// Properties of transition
		mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition );

		// String to hold the property name
		char id[ 256 ];

		// String to hold the passdown key
		char key[ 256 ];

		// Construct id
		sprintf( id, "_filter_%d", count );

		// Counstruct key
		sprintf( key, "%s.", name );

		// Just in case, let's assume that the filter here has a composite
		//mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "composite.geometry", "0%/0%:100%x100%" );
		//mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "composite.fill", 1 );

		// Pass all the key properties on the filter down
		mlt_properties_pass( MLT_FILTER_PROPERTIES( filter ), properties, key );
		mlt_properties_pass_list( MLT_FILTER_PROPERTIES( filter ), properties, "in, out, length" );

		// Ensure that filter is assigned
		mlt_properties_set_data( properties, id, filter, 0, ( mlt_destructor )mlt_filter_close, NULL );
	}
	else
	{
		// Indicate that an error has occurred
		error = 1;
	}

	// Cleanup
	free( type );

	// Return error condition
	return error;
}
Beispiel #10
0
// Image stack(able) method
static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{

	// Get the filter object
	mlt_filter filter = mlt_frame_pop_service( frame );

	// Get the filter's property object
	mlt_properties filter_properties = MLT_FILTER_PROPERTIES(filter);

	// Get the frame properties
	mlt_properties frame_properties = MLT_FRAME_PROPERTIES(frame);

	// Get the frame position
	mlt_position position = mlt_filter_get_position( filter, frame );

	// Get the new image
	int error = mlt_frame_get_image( frame, image, format, width, height, 1 );

	if( error != 0 )
		mlt_properties_debug( frame_properties, "error after mlt_frame_get_image() in autotrack_rectangle", stderr );

	mlt_service_lock( MLT_FILTER_SERVICE( filter ) );

	// Get the geometry object
	mlt_geometry geometry = mlt_properties_get_data(filter_properties, "filter_geometry", NULL);

	// Get the current geometry item
	struct mlt_geometry_item_s boundry;
	mlt_geometry_fetch(geometry, &boundry, position);

	// Get the motion vectors
	struct motion_vector_s *vectors = mlt_properties_get_data( frame_properties, "motion_est.vectors", NULL );

	// Cleanse the geometry item
	boundry.w = boundry.x < 0 ? boundry.w + boundry.x : boundry.w;
	boundry.h = boundry.y < 0 ? boundry.h + boundry.y : boundry.h;
	boundry.x = boundry.x < 0 ? 0 : boundry.x;
	boundry.y = boundry.y < 0 ? 0 : boundry.y;
	boundry.w = boundry.w < 0 ? 0 : boundry.w;
	boundry.h = boundry.h < 0 ? 0 : boundry.h;

	// How did the rectangle move?
	if( vectors != NULL &&
	    boundry.key != 1 ) // Paused?
	{

		int method = mlt_properties_get_int( filter_properties, "method" );

		// Get the size of macroblocks in pixel units
		int macroblock_height = mlt_properties_get_int( frame_properties, "motion_est.macroblock_height" );
		int macroblock_width = mlt_properties_get_int( frame_properties, "motion_est.macroblock_width" );
		int mv_buffer_width = *width / macroblock_width;

		caculate_motion( vectors, &boundry, macroblock_width, macroblock_height, mv_buffer_width, method, *width, *height );


		// Make the geometry object a real boy
		boundry.key = 1;
		boundry.f[0] = 1;
		boundry.f[1] = 1;
		boundry.f[2] = 1;
		boundry.f[3] = 1;
		boundry.f[4] = 1;
		mlt_geometry_insert(geometry, &boundry);
		mlt_geometry_interpolate(geometry);
	}

	mlt_service_unlock( MLT_FILTER_SERVICE( filter ) );

	if( mlt_properties_get_int( filter_properties, "debug" ) == 1 )
	{
		init_arrows( format, *width, *height );
		draw_rectangle_outline(*image, boundry.x, boundry.y, boundry.w, boundry.h, 100);
	}

	if( mlt_properties_get_int( filter_properties, "_serialize" ) == 1 )
	{
		// Add the vector change to the list
		mlt_geometry key_frames = mlt_properties_get_data( filter_properties, "motion_vector_list", NULL );
		if ( !key_frames )
		{
			key_frames = mlt_geometry_init();
			mlt_properties_set_data( filter_properties, "motion_vector_list", key_frames, 0,
			                         (mlt_destructor) mlt_geometry_close, (mlt_serialiser) mlt_geometry_serialise );
			if ( key_frames )
				mlt_geometry_set_length( key_frames, mlt_filter_get_length2( filter, frame ) );
		}
		if ( key_frames )
		{
			struct mlt_geometry_item_s item;
			item.frame = (int) mlt_frame_get_position( frame );
			item.key = 1;
			item.x = boundry.x;
			item.y = boundry.y;
			item.w = boundry.w;
			item.h = boundry.h;
			item.mix = 0;
			item.f[0] = item.f[1] = item.f[2] = item.f[3] = 1;
			item.f[4] = 0;
			mlt_geometry_insert( key_frames, &item );
		}
	}
	
	if( mlt_properties_get_int( filter_properties, "obscure" ) == 1 )
	{
		mlt_filter obscure = mlt_properties_get_data( filter_properties, "_obscure", NULL );

		mlt_properties_pass_list( MLT_FILTER_PROPERTIES(obscure), filter_properties, "in, out");

		// Because filter_obscure needs to be rewritten to use mlt_geometry
		char geom[100];
		sprintf( geom, "%d/%d:%dx%d", (int)boundry.x, (int)boundry.y, (int)boundry.w, (int)boundry.h );
		mlt_properties_set( MLT_FILTER_PROPERTIES( obscure ), "start", geom );
		mlt_properties_set( MLT_FILTER_PROPERTIES( obscure ), "end", geom );
	}
		
	if( mlt_properties_get_int( filter_properties, "collect" ) == 1 )
	{
		fprintf( stderr, "%d,%d,%d,%d\n", (int)boundry.x, (int)boundry.y, (int)boundry.w, (int)boundry.h );
		fflush( stdout );
	}

	return error;
}
Beispiel #11
0
static int get_frame( mlt_producer self, mlt_frame_ptr frame, int index )
{
	mlt_properties properties = MLT_PRODUCER_PROPERTIES(self);
	context cx = mlt_properties_get_data( properties, "context", NULL );

	if ( !cx )
	{
		// Allocate and initialize our context
		cx = mlt_pool_alloc( sizeof( struct context_s ) );
		memset( cx, 0, sizeof( *cx ) );
		mlt_properties_set_data( properties, "context", cx, 0, mlt_pool_release, NULL );
		cx->self = self;
		char *profile_name = mlt_properties_get( properties, "profile" );
		if ( !profile_name )
			profile_name = mlt_properties_get( properties, "mlt_profile" );
		mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( self ) );

		if ( profile_name )
		{
			cx->profile = mlt_profile_init( profile_name );
			cx->profile->is_explicit = 1;
		}
		else
		{
			cx->profile = mlt_profile_clone( profile );
			cx->profile->is_explicit = 0;
		}

		// Encapsulate a real producer for the resource
		cx->producer = mlt_factory_producer( cx->profile, NULL,
			mlt_properties_get( properties, "resource" ) );
		if ( ( profile_name && !strcmp( profile_name, "auto" ) ) ||
			mlt_properties_get_int( properties, "autoprofile" ) )
		{
			mlt_profile_from_producer( cx->profile, cx->producer );
			mlt_producer_close( cx->producer );
			cx->producer = mlt_factory_producer( cx->profile, NULL,	mlt_properties_get( properties, "resource" ) );
		}

		// Since we control the seeking, prevent it from seeking on its own
		mlt_producer_set_speed( cx->producer, 0 );
		cx->audio_position = -1;

		// We will encapsulate a consumer
		cx->consumer = mlt_consumer_new( cx->profile );
		// Do not use _pass_list on real_time so that it defaults to 0 in the absence of
		// an explicit real_time property.
		mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( cx->consumer ), "real_time",
			mlt_properties_get_int( properties, "real_time" ) );
		mlt_properties_pass_list( MLT_CONSUMER_PROPERTIES( cx->consumer ), properties,
			"buffer, prefill, deinterlace_method, rescale" );
	
		// Connect it all together
		mlt_consumer_connect( cx->consumer, MLT_PRODUCER_SERVICE( cx->producer ) );
		mlt_consumer_start( cx->consumer );
	}

	// Generate a frame
	*frame = mlt_frame_init( MLT_PRODUCER_SERVICE( self ) );
	if ( *frame )
	{
		// Seek the producer to the correct place
		// Calculate our positions
		double actual_position = (double) mlt_producer_frame( self );
		if ( mlt_producer_get_speed( self ) != 0 )
			actual_position *= mlt_producer_get_speed( self );
		mlt_position need_first = floor( actual_position );
		mlt_producer_seek( cx->producer,
			lrint( need_first * mlt_profile_fps( cx->profile ) / mlt_producer_get_fps( self ) ) );

		// Get the nested frame
		mlt_frame nested_frame = mlt_consumer_rt_frame( cx->consumer );

		// Stack the producer and our methods on the nested frame
		mlt_frame_push_service( *frame, nested_frame );
		mlt_frame_push_service( *frame, cx );
		mlt_frame_push_get_image( *frame, get_image );
		mlt_frame_push_audio( *frame, nested_frame );
		mlt_frame_push_audio( *frame, cx );
		mlt_frame_push_audio( *frame, get_audio );
		
		// Give the returned frame temporal identity
		mlt_frame_set_position( *frame, mlt_producer_position( self ) );
		
		// Store the nested frame on the produced frame for destruction
		mlt_properties frame_props = MLT_FRAME_PROPERTIES( *frame );
		mlt_properties_set_data( frame_props, "_producer_consumer.frame", nested_frame, 0, (mlt_destructor) mlt_frame_close, NULL );

		// Inform the normalizers about our video properties
		mlt_properties_set_double( frame_props, "aspect_ratio", mlt_profile_sar( cx->profile ) );
		mlt_properties_set_int( frame_props, "width", cx->profile->width );
		mlt_properties_set_int( frame_props, "height", cx->profile->height );
		mlt_properties_set_int( frame_props, "meta.media.width", cx->profile->width );
		mlt_properties_set_int( frame_props, "meta.media.height", cx->profile->height );
		mlt_properties_set_int( frame_props, "progressive", cx->profile->progressive );
	}

	// Calculate the next timecode
	mlt_producer_prepare_next( self );

	return 0;
}