Ejemplo n.º 1
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;
}
Ejemplo n.º 2
0
static void get_timecode_str( mlt_filter filter, mlt_frame frame, char* text )
{
	int frames = mlt_frame_get_position( frame );
	double fps = mlt_profile_fps( mlt_service_profile( MLT_FILTER_SERVICE( filter ) ) );
	char tc[12] = "";
	if (fps == 0)
	{
		strncat( text, "-", MAX_TEXT_LEN - strlen( text ) - 1 );
	}
	else
	{
		int seconds = frames / fps;
		frames = frames % lrint( fps );
		int minutes = seconds / 60;
		seconds = seconds % 60;
		int hours = minutes / 60;
		minutes = minutes % 60;
		sprintf(tc, "%.2d:%.2d:%.2d:%.2d", hours, minutes, seconds, frames);
		strncat( text, tc, MAX_TEXT_LEN - strlen( text ) - 1 );
	}
}
Ejemplo n.º 3
0
static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{
	// Get the filter
	mlt_filter filter = mlt_frame_pop_service( frame );

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

	mlt_service_lock( MLT_FILTER_SERVICE( filter ) );

	// Get the region transition
	mlt_transition transition = mlt_properties_get_data( properties, "_transition", NULL );

	// Create the transition if not available
	if ( transition == NULL )
	{
		// Create the transition
		mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) );
		transition = mlt_factory_transition( profile, "region", NULL );

		// Register with the filter
		mlt_properties_set_data( properties, "_transition", transition, 0, ( mlt_destructor )mlt_transition_close, NULL );

		// Pass a reference to this filter down
		mlt_properties_set_data( MLT_TRANSITION_PROPERTIES( transition ), "_region_filter", filter, 0, NULL, NULL );
	}

	mlt_service_unlock( MLT_FILTER_SERVICE( filter ) );

	// Pass all properties down
	mlt_properties_inherit( MLT_TRANSITION_PROPERTIES( transition ), properties );

	// Make the frame's position relative to this filter's in point
	mlt_frame_set_position( frame, mlt_filter_get_position( filter, frame ) );

	// Process the frame
	mlt_transition_process( transition, frame, NULL );

	return mlt_frame_get_image( frame, image, format, width, height, writable );
}
Ejemplo n.º 4
0
static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{
	// Pop the top of stack now
	mlt_filter filter = mlt_frame_pop_service( frame );

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

	// Get the image from the frame
	if ( error == 0 )
	{
		if ( filter != NULL )
		{
			// Get the filter properties
			mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
			mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) );

			// Structures for geometry
			struct geometry_s result;
			struct geometry_s start;
			struct geometry_s end;

			// Retrieve the position
			float position = mlt_filter_get_progress( filter, frame );

			// Now parse the geometries
			geometry_parse( &start, NULL, mlt_properties_get( properties, "start" ), profile->width, profile->height );
			geometry_parse( &end, &start, mlt_properties_get( properties, "end" ), profile->width, profile->height );

			// Do the calculation
			geometry_calculate( &result, &start, &end, position, *width, *height );

			// Now actually render it
			obscure_render( *image, *width, *height, result );
		}
	}

	return error;
}
Ejemplo n.º 5
0
static mlt_frame filter_process( mlt_filter filter, mlt_frame frame )
{
	mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame );
	if( mlt_frame_is_test_card( frame ) ) {
		// The producer does not generate video. This filter will create an
		// image on the producer's behalf.
		mlt_profile profile = mlt_service_profile(
			MLT_PRODUCER_SERVICE( mlt_frame_get_original_producer( frame ) ) );
		mlt_properties_set_int( frame_properties, "progressive", 1 );
		mlt_properties_set_double( frame_properties, "aspect_ratio", mlt_profile_sar( profile ) );
		mlt_properties_set_int( frame_properties, "meta.media.width", profile->width );
		mlt_properties_set_int( frame_properties, "meta.media.height", profile->height );
		// Tell the framework that there really is an image.
		mlt_properties_set_int( frame_properties, "test_image", 0 );
		// Push a callback to create the image.
		mlt_frame_push_get_image( frame, create_image );
	}
	mlt_frame_push_service( frame, filter );
	mlt_frame_push_get_image( frame, filter_get_image );

	return frame;
}
Ejemplo n.º 6
0
mlt_producer mlt_producer_cut( mlt_producer self, int in, int out )
{
	mlt_producer result = mlt_producer_new( mlt_service_profile( MLT_PRODUCER_SERVICE( self ) ) );
	mlt_producer parent = mlt_producer_cut_parent( self );
	mlt_properties properties = MLT_PRODUCER_PROPERTIES( result );
	mlt_properties parent_props = MLT_PRODUCER_PROPERTIES( parent );

	mlt_events_block( MLT_PRODUCER_PROPERTIES( result ), MLT_PRODUCER_PROPERTIES( result ) );
	// Special case - allow for a cut of the entire producer (this will squeeze all other cuts to 0)
	if ( in <= 0 )
		in = 0;
	if ( ( out < 0 || out >= mlt_producer_get_length( parent ) ) && !mlt_producer_is_blank( self ) )
		out = mlt_producer_get_length( parent ) - 1;

	mlt_properties_inc_ref( parent_props );
	mlt_properties_set_int( properties, "_cut", 1 );
	mlt_properties_set_data( properties, "_cut_parent", parent, 0, ( mlt_destructor )mlt_producer_close, NULL );
	mlt_properties_set_position( properties, "length", mlt_properties_get_position( parent_props, "length" ) );
	mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( parent_props, "aspect_ratio" ) );
	mlt_producer_set_in_and_out( result, in, out );

	return result;
}
Ejemplo n.º 7
0
static mlt_producer mlt_producer_clone( mlt_producer self )
{
	mlt_producer clone = NULL;
	mlt_properties properties = MLT_PRODUCER_PROPERTIES( self );
	char *resource = mlt_properties_get( properties, "resource" );
	char *service = mlt_properties_get( properties, "mlt_service" );
	mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( self ) );

	mlt_events_block( mlt_factory_event_object( ), mlt_factory_event_object( ) );

	if ( service != NULL )
		clone = mlt_factory_producer( profile, service, resource );

	if ( clone == NULL && resource != NULL )
		clone = mlt_factory_producer( profile, NULL, resource );

	if ( clone != NULL )
		mlt_properties_inherit( MLT_PRODUCER_PROPERTIES( clone ), properties );

	mlt_events_unblock( mlt_factory_event_object( ), mlt_factory_event_object( ) );

	return clone;
}
Ejemplo n.º 8
0
static int jack_sync( jack_transport_state_t state, jack_position_t *jack_pos, void *arg )
{
	mlt_filter filter = (mlt_filter) arg;
	mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
	mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE(filter) );
	mlt_position position = mlt_profile_fps( profile ) * jack_pos->frame / jack_pos->frame_rate + 0.5;
	int result = 1;

	mlt_log_debug( MLT_FILTER_SERVICE(filter), "%s frame %u rate %u pos %d last_pos %d\n",
		JACKSTATE(state), jack_pos->frame, jack_pos->frame_rate, position,
		mlt_properties_get_position( properties, "_last_pos" ) );
	if ( state == JackTransportStopped )
	{
		mlt_events_fire( properties, "jack-stopped", &position, NULL );
		mlt_properties_set_int( properties, "_sync_guard", 0 );
	}
	else if ( state == JackTransportStarting )
	{
		result = 0;
		if ( !mlt_properties_get_int( properties, "_sync_guard" ) )
		{
			mlt_properties_set_int( properties, "_sync_guard", 1 );
			mlt_events_fire( properties, "jack-started", &position, NULL );
		}
		else if ( position >= mlt_properties_get_position( properties, "_last_pos" ) - 2 )
		{
			mlt_properties_set_int( properties, "_sync_guard", 0 );
			result = 1;
		}
	}
	else
	{
		mlt_properties_set_int( properties, "_sync_guard", 0 );
	}

	return result;
}
Ejemplo n.º 9
0
static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )

{
  	// Get the real structure for this producer
	producer_ktitle this = producer->child;

	/* Generate a frame */
	*frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) );

	if ( *frame != NULL )
	{
		/* Obtain properties of frame and producer */
		mlt_properties properties = MLT_FRAME_PROPERTIES( *frame );

		/* Obtain properties of producer */
		mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer );

		/* Set the producer on the frame properties */
		mlt_properties_set_data( properties, "producer_kdenlivetitle", this, 0, NULL, NULL );

		/* Update timecode on the frame we're creating */
		mlt_frame_set_position( *frame, mlt_producer_position( producer ) );

		/* Set producer-specific frame properties */
		mlt_profile profile = mlt_service_profile ( MLT_PRODUCER_SERVICE( producer ) ) ;
		mlt_properties_set_int( properties, "progressive", ( profile ) ? profile->progressive : 1 );
		mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( producer_props, "aspect_ratio" ) );

		/* Push the get_image method */
		mlt_frame_push_get_image( *frame, producer_get_image );
	}

	/* Calculate the next timecode */
	mlt_producer_prepare_next( producer );

	return 0;
}
Ejemplo n.º 10
0
static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
{
	// Generate a frame
	*frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) );

	if ( *frame != NULL )
	{
		// Obtain properties of frame and producer
		mlt_properties properties = MLT_FRAME_PROPERTIES( *frame );

		// Obtain properties of producer
		mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer );

		// Set the producer on the frame properties
		mlt_properties_set_data( properties, "producer_colour", producer, 0, NULL, NULL );

		// Update timecode on the frame we're creating
		mlt_frame_set_position( *frame, mlt_producer_position( producer ) );

		// Set producer-specific frame properties
		mlt_properties_set_int( properties, "progressive", 1 );
		mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) );
		mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile ) );

		// colour is an alias for resource
		if ( mlt_properties_get( producer_props, "colour" ) != NULL )
			mlt_properties_set( producer_props, "resource", mlt_properties_get( producer_props, "colour" ) );
		
		// Push the get_image method
		mlt_frame_push_get_image( *frame, producer_get_image );
	}

	// Calculate the next timecode
	mlt_producer_prepare_next( producer );

	return 0;
}
Ejemplo n.º 11
0
static mlt_frame process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame )
{
	mlt_service service = MLT_TRANSITION_SERVICE(transition);

	if ( !GlslManager::init_chain( service ) ) {
		// Create the Movit effect chain
		EffectChain* chain = GlslManager::get_chain( service );
		mlt_profile profile = mlt_service_profile( service );
		Input* b_input = new MltInput( profile->width, profile->height );
		ImageFormat output_format;
		output_format.color_space = COLORSPACE_sRGB;
		output_format.gamma_curve = GAMMA_sRGB;
		chain->add_input( b_input );
		chain->add_output( output_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED );
		chain->set_dither_bits( 8 );

		Effect* effect = chain->add_effect( new MixEffect(),
			GlslManager::get_input( service ), b_input );

		// Save these new effects on properties for get_image
		mlt_properties properties = MLT_TRANSITION_PROPERTIES(transition);
		mlt_properties_set_data( properties, "movit effect", effect, 0, NULL, NULL );
		mlt_properties_set_data( properties, "movit input B", b_input, 0, NULL, NULL );
	}

	// Push the transition on to the frame
	mlt_frame_push_service( a_frame, transition );

	// Push the b_frame on to the stack
	mlt_frame_push_frame( a_frame, b_frame );

	// Push the transition method
	mlt_frame_push_get_image( a_frame, get_image );

	return a_frame;
}
Ejemplo n.º 12
0
static mlt_frame get_background_frame( mlt_producer producer )
{
	mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer );
	mlt_frame bg_frame = NULL;
	mlt_producer color_producer = mlt_properties_get_data( producer_properties, "_color_producer", NULL );

	if( !color_producer )
	{
		mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) );
		color_producer = mlt_factory_producer( profile, mlt_environment( "MLT_PRODUCER" ), "colour:" );
		mlt_properties_set_data( producer_properties, "_color_producer", color_producer, 0, ( mlt_destructor )mlt_producer_close, NULL );

		mlt_properties color_properties = MLT_PRODUCER_PROPERTIES( color_producer );
		mlt_properties_set( color_properties, "colour", FRAME_BACKGROUND_COLOR );
	}

	if( color_producer )
	{
		mlt_producer_seek( color_producer, 0 );
		mlt_service_get_frame( MLT_PRODUCER_SERVICE( color_producer ), &bg_frame, 0 );
	}

	return bg_frame;
}
Ejemplo n.º 13
0
static int filter_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;

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

	// Get the properties of the filter
	mlt_properties properties = MLT_FILTER_PROPERTIES( this );

	mlt_service_lock( MLT_FILTER_SERVICE( this ) );

	// Get the producer from the filter
	mlt_producer producer = mlt_properties_get_data( properties, "producer", NULL );

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

	// Get the resource to use
	char *resource = mlt_properties_get( properties, "resource" );

	// Get the old resource
	char *old_resource = mlt_properties_get( properties, "_old_resource" );

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

		// Register the composite for reuse/destruction
		if ( composite != NULL )
			mlt_properties_set_data( properties, "composite", composite, 0, ( mlt_destructor )mlt_transition_close, NULL );
	}

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

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

		if ( mlt_properties_get( properties, "composite.out" ) == NULL )
			mlt_properties_set_int( composite_properties, "out", mlt_properties_get_int( properties, "_out" ) );

		// Force a refresh
		mlt_properties_set_int( composite_properties, "refresh", 1 );
	}

	// Create a producer if don't have one
	if ( producer == NULL || ( old_resource != NULL && strcmp( resource, old_resource ) ) )
	{
		// Get the factory producer service
		char *factory = mlt_properties_get( properties, "factory" );

		// Create the producer
		mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( this ) );
		producer = mlt_factory_producer( profile, factory, resource );

		// If we have one
		if ( producer != NULL )
		{
			// Register the producer for reuse/destruction
			mlt_properties_set_data( properties, "producer", producer, 0, ( mlt_destructor )mlt_producer_close, NULL );

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

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

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

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

	mlt_service_unlock( MLT_FILTER_SERVICE( this ) );

	// Only continue if we have both producer and composite
	if ( composite != NULL && producer != NULL )
	{
		// Get the service of the producer
		mlt_service service = MLT_PRODUCER_SERVICE( producer );

		// We will get the 'b frame' from the producer
		mlt_frame b_frame = NULL;

		// Get the original producer position
		mlt_position position = mlt_filter_get_position( this, frame );

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

		// Resetting position to appease the composite transition
		mlt_frame_set_position( frame, position );

		// Get the b frame and process with composite if successful
		if ( mlt_service_get_frame( service, &b_frame, 0 ) == 0 )
		{
			// Get the a and b frame properties
			mlt_properties a_props = MLT_FRAME_PROPERTIES( frame );
			mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame );
			mlt_profile profile = mlt_service_profile( service );

			// Set the b frame to be in the same position and have same consumer requirements
			mlt_frame_set_position( b_frame, position );
			mlt_properties_set_int( b_props, "consumer_deinterlace", mlt_properties_get_int( a_props, "consumer_deinterlace" ) || mlt_properties_get_int( properties, "deinterlace" ) );

			// Check for the special case - no aspect ratio means no problem :-)
			if ( mlt_frame_get_aspect_ratio( b_frame ) == 0 )
				mlt_frame_set_aspect_ratio( b_frame, mlt_profile_sar( profile ) );
			if ( mlt_frame_get_aspect_ratio( frame ) == 0 )
				mlt_frame_set_aspect_ratio( frame, mlt_profile_sar( profile ) );

			if ( mlt_properties_get_int( properties, "distort" ) )
			{
				mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( composite ), "distort", 1 );
				mlt_properties_set_int( a_props, "distort", 1 );
				mlt_properties_set_int( b_props, "distort", 1 );
			}

			*format = mlt_image_yuv422;
			if ( mlt_properties_get_int( properties, "reverse" ) == 0 )
			{
				// Apply all filters that are attached to this filter to the b frame
				mlt_service_apply_filters( MLT_FILTER_SERVICE( this ), b_frame, 0 );

				// Process the frame
				mlt_transition_process( composite, frame, b_frame );

				// Get the image
				error = mlt_frame_get_image( frame, image, format, width, height, 1 );
			}
			else
			{
				char temp[ 132 ];
				int count = 0;
				uint8_t *alpha = NULL;
				const char *rescale = mlt_properties_get( a_props, "rescale.interp" );
				if ( rescale == NULL || !strcmp( rescale, "none" ) )
					rescale = "hyper";
				mlt_transition_process( composite, b_frame, frame );
				mlt_properties_set_int( a_props, "consumer_deinterlace", 1 );
				mlt_properties_set_int( b_props, "consumer_deinterlace", 1 );
				mlt_properties_set( a_props, "rescale.interp", rescale );
				mlt_properties_set( b_props, "rescale.interp", rescale );
				mlt_service_apply_filters( MLT_FILTER_SERVICE( this ), b_frame, 0 );
				error = mlt_frame_get_image( b_frame, image, format, width, height, 1 );
				alpha = mlt_frame_get_alpha_mask( b_frame );
				mlt_frame_set_image( frame, *image, *width * *height * 2, NULL );
				mlt_frame_set_alpha( frame, alpha, *width * *height, NULL );
				mlt_properties_set_int( a_props, "width", *width );
				mlt_properties_set_int( a_props, "height", *height );
				mlt_properties_set_int( a_props, "progressive", 1 );
				mlt_properties_inc_ref( b_props );
				strcpy( temp, "_b_frame" );
				while( mlt_properties_get_data( a_props, temp, NULL ) != NULL )
					sprintf( temp, "_b_frame%d", count ++ );
				mlt_properties_set_data( a_props, temp, b_frame, 0, ( mlt_destructor )mlt_frame_close, NULL );
			}
		}

		// Close the b frame
		mlt_frame_close( b_frame );
	}
	else
	{
		// Get the image from the frame without running fx
		error = mlt_frame_get_image( frame, image, format, width, height, 1 );
	}

	return error;
}
Ejemplo n.º 14
0
static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{
	int error = 0;

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

	// Pop the top of stack now
	mlt_filter filter = mlt_frame_pop_service( frame );
	mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) );

	// Retrieve the aspect ratio
	double aspect_ratio = mlt_deque_pop_back_double( MLT_FRAME_IMAGE_STACK( frame ) );
	double consumer_aspect = mlt_profile_sar( mlt_service_profile( MLT_FILTER_SERVICE( filter ) ) );

	// Correct Width/height if necessary
	if ( *width == 0 || *height == 0 )
	{
		*width = profile->width;
		*height = profile->height;
	}

	// Assign requested width/height from our subordinate
	int owidth = *width;
	int oheight = *height;

	// Check for the special case - no aspect ratio means no problem :-)
	if ( aspect_ratio == 0.0 )
		aspect_ratio = consumer_aspect;

	// Reset the aspect ratio
	mlt_properties_set_double( properties, "aspect_ratio", aspect_ratio );

	// XXX: This is a hack, but it forces the force_full_luma to apply by doing a RGB
	// conversion because range scaling only occurs on YUV->RGB. And we do it here,
	// after the deinterlace filter, which only operates in YUV to avoid a YUV->RGB->YUV->?.
	// Instead, it will go YUV->RGB->?.
	if ( mlt_properties_get_int( properties, "force_full_luma" ) )
		*format = mlt_image_rgb24a;

	// Hmmm...
	char *rescale = mlt_properties_get( properties, "rescale.interp" );
	if ( rescale != NULL && !strcmp( rescale, "none" ) )
		return mlt_frame_get_image( frame, image, format, width, height, writable );

	if ( mlt_properties_get_int( properties, "distort" ) == 0 )
	{
		// Normalise the input and out display aspect
		int normalised_width = profile->width;
		int normalised_height = profile->height;
		int real_width = mlt_properties_get_int( properties, "meta.media.width" );
		int real_height = mlt_properties_get_int( properties, "meta.media.height" );
		if ( real_width == 0 )
			real_width = mlt_properties_get_int( properties, "width" );
		if ( real_height == 0 )
			real_height = mlt_properties_get_int( properties, "height" );
		double input_ar = aspect_ratio * real_width / real_height;
		double output_ar = consumer_aspect * owidth / oheight;
		
// 		fprintf( stderr, "real %dx%d normalised %dx%d output %dx%d sar %f in-dar %f out-dar %f\n",
// 		real_width, real_height, normalised_width, normalised_height, owidth, oheight, aspect_ratio, input_ar, output_ar);

		// Optimised for the input_ar > output_ar case (e.g. widescreen on standard)
		int scaled_width = rint( ( input_ar * normalised_width ) / output_ar );
		int scaled_height = normalised_height;

		// Now ensure that our images fit in the output frame
		if ( scaled_width > normalised_width )
		{
			scaled_width = normalised_width;
			scaled_height = rint( ( output_ar * normalised_height ) / input_ar );
		}

		// Now calculate the actual image size that we want
		owidth = rint( scaled_width * owidth / normalised_width );
		oheight = rint( scaled_height * oheight / normalised_height );

		// Tell frame we have conformed the aspect to the consumer
		mlt_frame_set_aspect_ratio( frame, consumer_aspect );
	}

	mlt_properties_set_int( properties, "distort", 0 );

	// Now pass on the calculations down the line
	mlt_properties_set_int( properties, "resize_width", *width );
	mlt_properties_set_int( properties, "resize_height", *height );

	// If there will be padding, then we need packed image format.
	if ( *format == mlt_image_yuv420p )
	{
		int iwidth = mlt_properties_get_int( properties, "width" );
		int iheight = mlt_properties_get_int( properties, "height" );
		if ( iwidth < owidth || iheight < oheight )
			*format = mlt_image_yuv422;
	}

	// Now get the image
	if ( *format == mlt_image_yuv422 )
		owidth -= owidth % 2;
	error = mlt_frame_get_image( frame, image, format, &owidth, &oheight, writable );

	if ( error == 0 && *image )
	{
		int bpp;
		mlt_image_format_size( *format, owidth, oheight, &bpp );
		*image = frame_resize_image( frame, *width, *height, bpp );
	}

	return error;
}
Ejemplo n.º 15
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;
}
Ejemplo n.º 16
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_frame_pop_service( frame );
	*format = mlt_image_rgb24;
	mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "consumer_deinterlace", 1 );
	int error = mlt_frame_get_image( frame, image, format, width, height, 1 );

	if ( !error && *image )
	{
		videostab self = filter->child;
		mlt_position length = mlt_filter_get_length2( filter, frame );
		int h = *height;
		int w = *width;

		// Service locks are for concurrency control
		mlt_service_lock( MLT_FILTER_SERVICE( filter ) );
		if ( !self->initialized )
		{
			// Initialize our context
			self->initialized = 1;
			self->es = es_init( w, h );
			self->pos_i = (vc*) malloc( length * sizeof(vc) );
			self->pos_h = (vc*) malloc( length * sizeof(vc) );
			self->pos_y = (vc*) malloc( h * sizeof(vc) );
			self->rs = rs_init( w, h );
		}
		char *vectors = mlt_properties_get( MLT_FILTER_PROPERTIES(filter), "vectors" );
		if ( !vectors )
		{
			// Analyse
			int pos = (int) mlt_filter_get_position( filter, frame );
			self->pos_i[pos] = vc_add( pos == 0 ? vc_zero() : self->pos_i[pos - 1], es_estimate( self->es, *image ) );

			// On last frame
			if ( pos == length - 1 )
			{
				mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE(filter) );
				double fps =  mlt_profile_fps( profile );

				// Filter and store the results
				hipass( self->pos_i, self->pos_h, length, fps );
				serialize_vectors( self, length );
			}
		} else {
			// Apply
			if ( self->initialized != 2 )
			{
				// Load analysis results from property
				self->initialized = 2;
				deserialize_vectors( self, vectors, length );
			}
			if ( self->initialized == 2 )
			{
				// Stabilize
				float shutter_angle = mlt_properties_get_double( MLT_FRAME_PROPERTIES(frame) , "shutterangle" );
				float pos = mlt_filter_get_position( filter, frame );
				int i;

				for (i = 0; i < h; i ++)
					self->pos_y[i] = interp( self->lanc_kernels,self->pos_h, length, pos + (i - h / 2.0) * shutter_angle / (h * 360.0) );
				rs_resample( self->lanc_kernels,self->rs, *image, self->pos_y );
			}
		}
		mlt_service_unlock( MLT_FILTER_SERVICE( filter ) );
	}
	return error;
}
Ejemplo n.º 17
0
double mlt_producer_get_fps( mlt_producer self )
{
	mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( self ) );
	return mlt_profile_fps( profile );
}
Ejemplo n.º 18
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, strlen( keywords ) -1 );
										strcat( result, "#" );
										ct++;
									}
									else
									{
										strcat( result, keywords );
									}
								}
								else if ( !strcmp( keywords, "timecode" ) )
								{
									// special case: replace #timecode# with current frame timecode
									int pos = mlt_properties_get_int( feed, "position" );
									char *tc = frame_to_timecode( pos, mlt_profile_fps( mlt_service_profile( MLT_FILTER_SERVICE( filter ) ) ) );
									strncat( result, tc, sizeof( result ) - strlen( result ) - 1 );
									free( tc );
								}
								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';
									strcat( result, s );
								}
                                                                else if ( !strcmp( keywords, "now" ) )
                                                                {
                                                                        time_t now;
                                                                        struct tm *t;
                                                                        char s[] = "xx:xx ";

                                                                        time (&now);
                                                                        t = localtime(&now);

                                                                        snprintf( s, sizeof(s), "%02d:%02d", t->tm_hour, t->tm_min);
									s[sizeof( s )] = '\0';
									strcat( result, s );
                                                                }
								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;
}
Ejemplo n.º 19
0
static mlt_frame filter_process( mlt_filter filter, mlt_frame frame )
{
	if ( mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "active" ) )
	{
		// Push the get_image method on to the stack
		mlt_frame_push_service( frame, mlt_service_profile( MLT_FILTER_SERVICE( filter ) ) );
		mlt_frame_push_get_image( frame, filter_get_image );
	}
	else
	{
		mlt_properties filter_props = MLT_FILTER_PROPERTIES( filter );
		mlt_properties frame_props = MLT_FRAME_PROPERTIES( frame );
		int left   = mlt_properties_get_int( filter_props, "left" );
		int right  = mlt_properties_get_int( filter_props, "right" );
		int top    = mlt_properties_get_int( filter_props, "top" );
		int bottom = mlt_properties_get_int( filter_props, "bottom" );
		int width  = mlt_properties_get_int( frame_props, "meta.media.width" );
		int height = mlt_properties_get_int( frame_props, "meta.media.height" );
		int use_profile = mlt_properties_get_int( filter_props, "use_profile" );
		mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) );

		if ( use_profile )
		{
			top = top * height / profile->height;
			bottom = bottom * height / profile->height;
			left = left * width / profile->width;
			right = right * width / profile->width;
		}
		if ( mlt_properties_get_int( filter_props, "center" ) )
		{
			double aspect_ratio = mlt_frame_get_aspect_ratio( frame );
			if ( aspect_ratio == 0.0 )
				aspect_ratio = mlt_profile_sar( profile );
			double input_ar = aspect_ratio * width / height;
			double output_ar = mlt_profile_dar( mlt_service_profile( MLT_FILTER_SERVICE(filter) ) );
			int bias = mlt_properties_get_int( filter_props, "center_bias" );
			
			if ( input_ar > output_ar )
			{
				left = right = ( width - rint( output_ar * height / aspect_ratio ) ) / 2;
				if ( abs(bias) > left )
					bias = bias < 0 ? -left : left;
				else if ( use_profile )
					bias = bias * width / profile->width;
				left -= bias;
				right += bias;
			}
			else
			{
				top = bottom = ( height - rint( aspect_ratio * width / output_ar ) ) / 2;
				if ( abs(bias) > top )
					bias = bias < 0 ? -top : top;
				else if ( use_profile )
					bias = bias * height / profile->height;
				top -= bias;
				bottom += bias;
			}
		}		

		// Coerce the output to an even width because subsampled YUV with odd widths is too
		// risky for downstream processing to handle correctly.
		left += ( width - left - right ) & 1;
		if ( width - left - right < 8 )
			left = right = 0;
		if ( height - top - bottom < 8 )
			top = bottom = 0;
		mlt_properties_set_int( frame_props, "crop.left", left );
		mlt_properties_set_int( frame_props, "crop.right", right );
		mlt_properties_set_int( frame_props, "crop.top", top );
		mlt_properties_set_int( frame_props, "crop.bottom", bottom );
		mlt_properties_set_int( frame_props, "crop.original_width", width );
		mlt_properties_set_int( frame_props, "crop.original_height", height );
		mlt_properties_set_int( frame_props, "meta.media.width", width - left - right );
		mlt_properties_set_int( frame_props, "meta.media.height", height - top - bottom );
	}
	return frame;
}
Ejemplo n.º 20
0
    mlt_frame getFrame()
    {
        struct timeval now;
        struct timespec tm;
        double fps = mlt_producer_get_fps( getProducer() );
        mlt_position position = mlt_producer_position( getProducer() );
        mlt_frame frame = mlt_cache_get_frame( m_cache, position );

        // Allow the buffer to fill to the requested initial buffer level.
        if ( m_isBuffering )
        {
            int prefill = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "prefill" );
            int buffer = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "buffer" );

            m_isBuffering = false;
            prefill = prefill > buffer ? buffer : prefill;
            pthread_mutex_lock( &m_mutex );
            while ( mlt_deque_count( m_queue ) < prefill )
            {
                // Wait up to buffer/fps seconds
                gettimeofday( &now, NULL );
                long usec = now.tv_sec * 1000000 + now.tv_usec;
                usec += 1000000 * buffer / fps;
                tm.tv_sec = usec / 1000000;
                tm.tv_nsec = (usec % 1000000) * 1000;
                if ( pthread_cond_timedwait( &m_condition, &m_mutex, &tm ) )
                    break;
            }
            pthread_mutex_unlock( &m_mutex );
        }

        if ( !frame )
        {
            // Wait if queue is empty
            pthread_mutex_lock( &m_mutex );
            while ( mlt_deque_count( m_queue ) < 1 )
            {
                // Wait up to twice frame duration
                gettimeofday( &now, NULL );
                long usec = now.tv_sec * 1000000 + now.tv_usec;
                usec += 2000000 / fps;
                tm.tv_sec = usec / 1000000;
                tm.tv_nsec = (usec % 1000000) * 1000;
                if ( pthread_cond_timedwait( &m_condition, &m_mutex, &tm ) )
                    // Stop waiting if error (timed out)
                    break;
            }
            frame = ( mlt_frame ) mlt_deque_pop_front( m_queue );
            pthread_mutex_unlock( &m_mutex );

            // add to cache
            if ( frame )
            {
                mlt_frame_set_position( frame, position );
                mlt_cache_put_frame( m_cache, frame );
            }
        }

        // Set frame timestamp and properties
        if ( frame )
        {
            mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) );
            mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
            mlt_properties_set_int( properties, "progressive", profile->progressive );
            mlt_properties_set_int( properties, "meta.media.progressive", profile->progressive );
            mlt_properties_set_int( properties, "top_field_first", m_topFieldFirst );
            mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile ) );
            mlt_properties_set_int( properties, "meta.media.sample_aspect_num", profile->sample_aspect_num );
            mlt_properties_set_int( properties, "meta.media.sample_aspect_den", profile->sample_aspect_den );
            mlt_properties_set_int( properties, "meta.media.frame_rate_num", profile->frame_rate_num );
            mlt_properties_set_int( properties, "meta.media.frame_rate_den", profile->frame_rate_den );
            mlt_properties_set_int( properties, "width", profile->width );
            mlt_properties_set_int( properties, "meta.media.width", profile->width );
            mlt_properties_set_int( properties, "height", profile->height );
            mlt_properties_set_int( properties, "meta.media.height", profile->height );
            mlt_properties_set_int( properties, "format", mlt_image_yuv422 );
            mlt_properties_set_int( properties, "colorspace", m_colorspace );
            mlt_properties_set_int( properties, "meta.media.colorspace", m_colorspace );
            mlt_properties_set_int( properties, "audio_frequency", 48000 );
            mlt_properties_set_int( properties, "audio_channels",
                                    mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" ) );
        }
        else
            mlt_log_warning( getProducer(), "buffer underrun\n" );

        return frame;
    }
Ejemplo n.º 21
0
    bool start( mlt_profile profile = 0 )
    {
        if ( m_started )
            return false;
        try
        {
            // Initialize some members
            m_vancLines = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "vanc" );
            if ( m_vancLines == -1 )
                m_vancLines = profile->height <= 512 ? 26 : 32;

            if ( !profile )
                profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) );

            // Get the display mode
            BMDDisplayMode displayMode = getDisplayMode( profile, m_vancLines );
            if ( displayMode == (BMDDisplayMode) bmdDisplayModeNotSupported )
            {
                mlt_log_info( getProducer(), "profile = %dx%d %f fps %s\n", profile->width, profile->height,
                              mlt_profile_fps( profile ), profile->progressive? "progressive" : "interlace" );
                throw "Profile is not compatible with decklink.";
            }

            // Determine if supports input format detection
#ifdef WIN32
            BOOL doesDetectFormat = FALSE;
#else
            bool doesDetectFormat = false;
#endif
            IDeckLinkAttributes *decklinkAttributes = 0;
            if ( m_decklink->QueryInterface( IID_IDeckLinkAttributes, (void**) &decklinkAttributes ) == S_OK )
            {
                if ( decklinkAttributes->GetFlag( BMDDeckLinkSupportsInputFormatDetection, &doesDetectFormat ) != S_OK )
                    doesDetectFormat = false;
                SAFE_RELEASE( decklinkAttributes );
            }
            mlt_log_verbose( getProducer(), "%s format detection\n", doesDetectFormat ? "supports" : "does not support" );

            // Enable video capture
            BMDPixelFormat pixelFormat = bmdFormat8BitYUV;
            BMDVideoInputFlags flags = doesDetectFormat ? bmdVideoInputEnableFormatDetection : bmdVideoInputFlagDefault;
            if ( S_OK != m_decklinkInput->EnableVideoInput( displayMode, pixelFormat, flags ) )
                throw "Failed to enable video capture.";

            // Enable audio capture
            BMDAudioSampleRate sampleRate = bmdAudioSampleRate48kHz;
            BMDAudioSampleType sampleType = bmdAudioSampleType16bitInteger;
            int channels = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" );
            if ( S_OK != m_decklinkInput->EnableAudioInput( sampleRate, sampleType, channels ) )
                throw "Failed to enable audio capture.";

            // Start capture
            m_dropped = 0;
            mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "dropped", m_dropped );
            m_started = m_decklinkInput->StartStreams() == S_OK;
            if ( !m_started )
                throw "Failed to start capture.";
        }
        catch ( const char *error )
        {
            m_decklinkInput->DisableVideoInput();
            mlt_log_error( getProducer(), "%s\n", error );
            return false;
        }
        return true;
    }
Ejemplo n.º 22
0
static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{
	// Get the b frame from the stack
	mlt_frame b_frame = mlt_frame_pop_frame( a_frame );

	// Get the transition object
	mlt_transition transition = mlt_frame_pop_service( a_frame );

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

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

	// Get the properties of the b frame
	mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame );

	// Image, format, width, height and image for the b frame
	uint8_t *b_image = NULL;
	mlt_image_format b_format = mlt_image_rgb24a;
	int b_width = mlt_properties_get_int( b_props, "meta.media.width" );
	int b_height = mlt_properties_get_int( b_props, "meta.media.height" );
	double b_ar = mlt_frame_get_aspect_ratio( b_frame );
	double b_dar = b_ar * b_width / b_height;

	// Assign the current position
	mlt_position position =  mlt_transition_get_position( transition, a_frame );

	int mirror = mlt_properties_get_position( properties, "mirror" );
	int length = mlt_transition_get_length( transition );
	if ( mlt_properties_get_int( properties, "always_active" ) )
	{
		mlt_properties props = mlt_properties_get_data( b_props, "_producer", NULL );
		mlt_position in = mlt_properties_get_int( props, "in" );
		mlt_position out = mlt_properties_get_int( props, "out" );
		length = out - in + 1;
	}

	// Obtain the normalised width and height from the a_frame
	mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( transition ) );
	int normalised_width = profile->width;
	int normalised_height = profile->height;

	double consumer_ar = mlt_profile_sar( profile );

	if ( mirror && position > length / 2 )
		position = abs( position - length );

	// Fetch the a frame image
	*format = mlt_image_rgb24a;
	int error = mlt_frame_get_image( a_frame, image, format, width, height, 1 );
	if (error || !image)
		return error;

	// Calculate the region now
	mlt_rect result = {0, 0, normalised_width, normalised_height, 1.0};
	mlt_service_lock( MLT_TRANSITION_SERVICE( transition ) );

	if (mlt_properties_get(properties, "geometry"))
	{
		// Structures for geometry
		struct mlt_geometry_item_s geometry;
		composite_calculate( transition, &geometry, normalised_width, normalised_height, ( double )position );
		result.x = geometry.x;
		result.y = geometry.y;
		result.w = geometry.w;
		result.h = geometry.h;
		result.o = geometry.mix / 100.0f;
	}
	else if (mlt_properties_get(properties, "rect"))
	{
		// Determine length and obtain cycle
		double cycle = mlt_properties_get_double( properties, "cycle" );
	
		// Allow a repeat cycle
		if ( cycle >= 1 )
			length = cycle;
		else if ( cycle > 0 )
			length *= cycle;
		
		mlt_position anim_pos = repeat_position(properties, "rect", position, length);
		result = mlt_properties_anim_get_rect(properties, "rect", anim_pos, length);
		if (mlt_properties_get(properties, "rect") && strchr(mlt_properties_get(properties, "rect"), '%')) {
			result.x *= normalised_width;
			result.y *= normalised_height;
			result.w *= normalised_width;
			result.h *= normalised_height;
		}
		result.o = (result.o == DBL_MIN)? 1.0 : MIN(result.o, 1.0);
	}
	mlt_service_unlock( MLT_TRANSITION_SERVICE( transition ) );

	double geometry_w = result.w;
	double geometry_h = result.h;

	if ( !mlt_properties_get_int( properties, "fill" ) )
	{
		double geometry_dar = result.w * consumer_ar / result.h;

		if ( b_dar > geometry_dar )
		{
			result.w = MIN( result.w, b_width * b_ar / consumer_ar );
			result.h = result.w * consumer_ar / b_dar;
		}
		else
		{
			result.h = MIN( result.h, b_height );
			result.w = result.h * b_dar / consumer_ar;
		}
	}

	// Fetch the b frame image
	result.w = ( result.w * *width / normalised_width );
	result.h = ( result.h * *height / normalised_height );
	result.x = ( result.x * *width / normalised_width );
	result.y = ( result.y * *height / normalised_height );

	if (mlt_properties_get_int(properties, "b_scaled")) {
		// Request b frame image size just what is needed.
		b_width = result.w;
		b_height = result.h;
		// Set the rescale interpolation to match the frame
		mlt_properties_set( b_props, "rescale.interp", mlt_properties_get( a_props, "rescale.interp" ) );
	} else {
		// Request full resolution of b frame image.
		mlt_properties_set_int( b_props, "rescale_width", b_width );
		mlt_properties_set_int( b_props, "rescale_height", b_height );

		// Suppress padding and aspect normalization.
		mlt_properties_set( b_props, "rescale.interp", "none" );
	}

	// This is not a field-aware transform.
	mlt_properties_set_int( b_props, "consumer_deinterlace", 1 );

	error = mlt_frame_get_image( b_frame, &b_image, &b_format, &b_width, &b_height, 0 );
	if (error || !b_image) {
		// Remove potentially large image on the B frame. 
		mlt_frame_set_image( b_frame, NULL, 0, NULL );
		return error;
	}

	// Check that both images are of the correct format and process
	if ( *format == mlt_image_rgb24a && b_format == mlt_image_rgb24a )
	{
		double sw, sh;
		// Get values from the transition
		double scale_x = mlt_properties_anim_get_double( properties, "scale_x", position, length );
		double scale_y = mlt_properties_anim_get_double( properties, "scale_y", position, length );
		int scale = mlt_properties_get_int( properties, "scale" );
		double geom_scale_x = (double) b_width / result.w;
		double geom_scale_y = (double) b_height / result.h;
		struct sliced_desc desc = {
			.a_image = *image,
			.b_image = b_image,
			.interp = interpBL_b32,
			.a_width = *width,
			.a_height = *height,
			.b_width = b_width,
			.b_height = b_height,
			.lower_x = -(result.x + result.w / 2.0), // center
			.lower_y = -(result.y + result.h / 2.0), // middle
			.mix = result.o,
			.x_offset = (double) b_width / 2.0,
			.y_offset = (double) b_height / 2.0,
			.b_alpha = mlt_properties_get_int( properties, "b_alpha" ),
			// Affine boundaries
			.minima = 0,
			.xmax = b_width - 1,
			.ymax = b_height - 1
		};

		// Recalculate vars if alignment supplied.
		if ( mlt_properties_get( properties, "halign" ) || mlt_properties_get( properties, "valign" ) )
		{
			double halign = alignment_parse( mlt_properties_get( properties, "halign" ) );
			double valign = alignment_parse( mlt_properties_get( properties, "valign" ) );
			desc.x_offset = halign * b_width / 2.0;
			desc.y_offset = valign * b_height / 2.0;
			desc.lower_x = -(result.x + geometry_w * halign / 2.0f);
			desc.lower_y = -(result.y + geometry_h * valign / 2.0f);
		}

		affine_init( desc.affine.matrix );

		// Compute the affine transform
		get_affine( &desc.affine, transition, ( double )position, length );
		desc.dz = MapZ( desc.affine.matrix, 0, 0 );
		if ( (int) fabs( desc.dz * 1000 ) < 25 )
			return 0;

		// Factor scaling into the transformation based on output resolution.
		if ( mlt_properties_get_int( properties, "distort" ) )
		{
			scale_x = geom_scale_x * ( scale_x == 0 ? 1 : scale_x );
			scale_y = geom_scale_y * ( scale_y == 0 ? 1 : scale_y );
		}
		else
		{
			// Determine scale with respect to aspect ratio.
			double consumer_dar = consumer_ar * normalised_width / normalised_height;
			
			if ( b_dar > consumer_dar )
			{
				scale_x = geom_scale_x * ( scale_x == 0 ? 1 : scale_x );
				scale_y = geom_scale_x * ( scale_y == 0 ? 1 : scale_y );
				scale_y *= b_ar / consumer_ar;
			}
			else
			{
				scale_x = geom_scale_y * ( scale_x == 0 ? 1 : scale_x );
				scale_y = geom_scale_y * ( scale_y == 0 ? 1 : scale_y );
				scale_x *= consumer_ar / b_ar;
			}
		}
		if ( scale )
		{
			affine_max_output( desc.affine.matrix, &sw, &sh, desc.dz, *width, *height );
			affine_scale( desc.affine.matrix, sw * MIN( geom_scale_x, geom_scale_y ), sh * MIN( geom_scale_x, geom_scale_y ) );
		}
		else if ( scale_x != 0 && scale_y != 0 )
		{
			affine_scale( desc.affine.matrix, scale_x, scale_y );
		}


		char *interps = mlt_properties_get( a_props, "rescale.interp" );
		// Copy in case string is changed.
		if ( interps )
			interps = strdup( interps );

		// Set the interpolation function
		if ( interps == NULL || strcmp( interps, "nearest" ) == 0 || strcmp( interps, "neighbor" ) == 0 || strcmp( interps, "tiles" ) == 0 || strcmp( interps, "fast_bilinear" ) == 0 )
		{
			desc.interp = interpNN_b32;
			// uses lrintf. Values should be >= -0.5 and < max + 0.5
			desc.minima -= 0.5;
			desc.xmax += 0.49;
			desc.ymax += 0.49;
		}
		else if ( strcmp( interps, "bilinear" ) == 0 )
		{
			desc.interp = interpBL_b32;
			// uses floorf.
		}
		else if ( strcmp( interps, "bicubic" ) == 0 ||  strcmp( interps, "hyper" ) == 0 || strcmp( interps, "sinc" ) == 0 || strcmp( interps, "lanczos" ) == 0 || strcmp( interps, "spline" ) == 0 )
		{
			// TODO: lanczos 8x8
			// TODO: spline 4x4 or 6x6
			desc.interp = interpBC_b32;
			// uses ceilf. Values should be > -1 and <= max.
			desc.minima -= 1;
		}
		free( interps );

		// Do the transform with interpolation
		int threads = mlt_properties_get_int(properties, "threads");
		threads = CLAMP(threads, 0, mlt_slices_count_normal());
		if (threads == 1)
			sliced_proc(0, 0, 1, &desc);
		else
			mlt_slices_run_normal(threads, sliced_proc, &desc);
		
		// Remove potentially large image on the B frame. 
		mlt_frame_set_image( b_frame, NULL, 0, NULL );
	}

	return 0;
}
Ejemplo n.º 23
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;
}
Ejemplo n.º 24
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;
}
Ejemplo n.º 25
0
bool ServiceManager::initialize(int width, int height)
{
    if (effects)
        return true;

    mlt_properties properties = MLT_SERVICE_PROPERTIES(service);

    // Create and initialize Effects
    const char* fileName = mlt_properties_get(properties, "resource");
    if (!fileName) {
        mlt_log(service, MLT_LOG_ERROR, "No 'resource' property found\n");
        return false;
    }
    bool isTransparent = mlt_properties_get_int(properties, "transparent") || mlt_service_identify(service) == filter_type;
    parameters = new ServiceParameters(service);
    effects = WebVfx::createEffects(fileName, width, height,
                                    parameters, isTransparent);
    if (!effects) {
        mlt_log(service, MLT_LOG_ERROR,
                "Failed to create WebVfx Effects for resource %s\n", fileName);
        return false;
    }

    // Iterate over image map - save source and target image names,
    // and create an ImageProducer for each extra image.
    char* factory = mlt_properties_get(properties, "factory");
    WebVfx::Effects::ImageTypeMapIterator it(effects->getImageTypeMap());
    while (it.hasNext()) {
        it.next();

        const QString& imageName = it.key();

        switch (it.value()) {

        case WebVfx::Effects::SourceImageType:
            sourceImageName = imageName;
            break;

        case WebVfx::Effects::TargetImageType:
            targetImageName = imageName;
            break;

        case WebVfx::Effects::ExtraImageType:
        {
            if (!imageProducers)
                imageProducers = new std::vector<ImageProducer*>(3);

            // Property prefix "producer.<name>."
            QString producerPrefix("producer.");
            producerPrefix.append(imageName).append(".");

            // Find producer.<name>.resource property
            QString resourceName(producerPrefix);
            resourceName.append("resource");
            char* resource = mlt_properties_get(properties, resourceName.toLatin1().constData());
            if (resource) {
                mlt_producer producer = mlt_factory_producer(mlt_service_profile(service), factory, resource);
                if (!producer) {
                    mlt_log(service, MLT_LOG_ERROR, "WebVfx failed to create extra image producer for %s\n", resourceName.toLatin1().constData());
                    return false;
                }
                // Copy producer.<name>.* properties onto producer
                mlt_properties_pass(MLT_PRODUCER_PROPERTIES(producer), properties, producerPrefix.toLatin1().constData());
                // Append ImageProducer to vector
                imageProducers->insert(imageProducers->end(), new ImageProducer(imageName, producer));
            }
            else
                mlt_log(service, MLT_LOG_WARNING, "WebVfx no producer resource property specified for extra image %s\n", resourceName.toLatin1().constData());
            break;
        }

        default:
            mlt_log(service, MLT_LOG_ERROR, "Invalid WebVfx image type %d\n", it.value());
            break;
        }
    }

    return true;
}
Ejemplo n.º 26
0
static void mlt_consumer_property_changed( mlt_properties owner, mlt_consumer self, char *name )
{
	if ( !strcmp( name, "mlt_profile" ) )
	{
		// Get the properies
		mlt_properties properties = MLT_CONSUMER_PROPERTIES( self );

		// Get the current profile
		mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) );

		// Load the new profile
		mlt_profile new_profile = mlt_profile_init( mlt_properties_get( properties, name ) );

		if ( new_profile )
		{
			// Copy the profile
			if ( profile != NULL )
			{
				free( profile->description );
				memcpy( profile, new_profile, sizeof( struct mlt_profile_s ) );
				profile->description = strdup( new_profile->description );
			}
			else
			{
				profile = new_profile;
			}

			// Apply to properties
			apply_profile_properties( self, profile, properties );
			mlt_profile_close( new_profile );
		}
 	}
	else if ( !strcmp( name, "frame_rate_num" ) )
	{
		mlt_properties properties = MLT_CONSUMER_PROPERTIES( self );
		mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) );
		if ( profile )
		{
			profile->frame_rate_num = mlt_properties_get_int( properties, "frame_rate_num" );
			mlt_properties_set_double( properties, "fps", mlt_profile_fps( profile ) );
		}
	}
	else if ( !strcmp( name, "frame_rate_den" ) )
	{
		mlt_properties properties = MLT_CONSUMER_PROPERTIES( self );
		mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) );
		if ( profile )
		{
			profile->frame_rate_den = mlt_properties_get_int( properties, "frame_rate_den" );
			mlt_properties_set_double( properties, "fps", mlt_profile_fps( profile ) );
		}
	}
	else if ( !strcmp( name, "width" ) )
	{
		mlt_properties properties = MLT_CONSUMER_PROPERTIES( self );
		mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) );
		if ( profile )
			profile->width = mlt_properties_get_int( properties, "width" );
	}
	else if ( !strcmp( name, "height" ) )
	{
		mlt_properties properties = MLT_CONSUMER_PROPERTIES( self );
		mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) );
		if ( profile )
			profile->height = mlt_properties_get_int( properties, "height" );
	}
	else if ( !strcmp( name, "progressive" ) )
	{
		mlt_properties properties = MLT_CONSUMER_PROPERTIES( self );
		mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) );
		if ( profile )
			profile->progressive = mlt_properties_get_int( properties, "progressive" );
	}
	else if ( !strcmp( name, "sample_aspect_num" ) )
	{
		mlt_properties properties = MLT_CONSUMER_PROPERTIES( self );
		mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) );
		if ( profile )
		{
			profile->sample_aspect_num = mlt_properties_get_int( properties, "sample_aspect_num" );
			mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile )  );
		}
	}
	else if ( !strcmp( name, "sample_aspect_den" ) )
	{
		mlt_properties properties = MLT_CONSUMER_PROPERTIES( self );
		mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) );
		if ( profile )
		{
			profile->sample_aspect_den = mlt_properties_get_int( properties, "sample_aspect_den" );
			mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile )  );
		}
	}
	else if ( !strcmp( name, "display_aspect_num" ) )
	{
		mlt_properties properties = MLT_CONSUMER_PROPERTIES( self );
		mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) );
		if ( profile )
		{
			profile->display_aspect_num = mlt_properties_get_int( properties, "display_aspect_num" );
			mlt_properties_set_double( properties, "display_ratio", mlt_profile_dar( profile )  );
		}
	}
	else if ( !strcmp( name, "display_aspect_den" ) )
	{
		mlt_properties properties = MLT_CONSUMER_PROPERTIES( self );
		mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) );
		if ( profile )
		{
			profile->display_aspect_den = mlt_properties_get_int( properties, "display_aspect_den" );
			mlt_properties_set_double( properties, "display_ratio", mlt_profile_dar( profile )  );
		}
	}
	else if ( !strcmp( name, "colorspace" ) )
	{
		mlt_properties properties = MLT_CONSUMER_PROPERTIES( self );
		mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) );
		if ( profile )
			profile->colorspace = mlt_properties_get_int( properties, "colorspace" );
	}
}
Ejemplo n.º 27
0
static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
{
	// Obtain properties of frame
	mlt_properties properties = MLT_FRAME_PROPERTIES( frame );

	// Obtain the producer for this frame
	mlt_producer producer = mlt_properties_get_data( properties, "producer_colour", NULL );

	mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) );

	// Obtain properties of producer
	mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer );

	// Get the current and previous colour strings
	char *now = mlt_properties_get( producer_props, "resource" );
	char *then = mlt_properties_get( producer_props, "_resource" );

	// Get the current image and dimensions cached in the producer
	int size = 0;
	uint8_t *image = mlt_properties_get_data( producer_props, "image", &size );
	int current_width = mlt_properties_get_int( producer_props, "_width" );
	int current_height = mlt_properties_get_int( producer_props, "_height" );
	mlt_image_format current_format = mlt_properties_get_int( producer_props, "_format" );

	// Parse the colour
	if ( now && strchr( now, '/' ) )
	{
		now = strdup( strrchr( now, '/' ) + 1 );
		mlt_properties_set( producer_props, "resource", now );
		free( now );
		now = mlt_properties_get( producer_props, "resource" );
	}
	mlt_color color = mlt_properties_get_color( producer_props, "resource" );

	if ( mlt_properties_get( producer_props, "mlt_image_format") )
		*format = mlt_image_format_id( mlt_properties_get( producer_props, "mlt_image_format") );

	// Choose suitable out values if nothing specific requested
	if ( *format == mlt_image_none || *format == mlt_image_glsl )
		*format = mlt_image_rgb24a;
	if ( *width <= 0 )
		*width = mlt_service_profile( MLT_PRODUCER_SERVICE(producer) )->width;
	if ( *height <= 0 )
		*height = mlt_service_profile( MLT_PRODUCER_SERVICE(producer) )->height;
	
	// Choose default image format if specific request is unsupported
	if (*format!=mlt_image_yuv420p  && *format!=mlt_image_yuv422  && *format!=mlt_image_rgb24 && *format!= mlt_image_glsl && *format!= mlt_image_glsl_texture)
		*format = mlt_image_rgb24a;

	// See if we need to regenerate
	if ( !now || ( then && strcmp( now, then ) ) || *width != current_width || *height != current_height || *format != current_format )
	{
		// Color the image
		int i = *width * *height + 1;
		int bpp;

		// Allocate the image
		size = mlt_image_format_size( *format, *width, *height, &bpp );
		uint8_t *p = image = mlt_pool_alloc( size );

		// Update the producer
		mlt_properties_set_data( producer_props, "image", image, size, mlt_pool_release, NULL );
		mlt_properties_set_int( producer_props, "_width", *width );
		mlt_properties_set_int( producer_props, "_height", *height );
		mlt_properties_set_int( producer_props, "_format", *format );
		mlt_properties_set( producer_props, "_resource", now );

		mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) );

		switch ( *format )
		{
		case mlt_image_yuv420p:
		{
			int plane_size =  *width * *height;
			uint8_t y, u, v;

			RGB2YUV_601_SCALED( color.r, color.g, color.b, y, u, v );
			memset(p + 0, y, plane_size);
			memset(p + plane_size, u, plane_size/4);
			memset(p + plane_size + plane_size/4, v, plane_size/4);
			mlt_properties_set_int( properties, "colorspace", 601 );
			break;
		}
		case mlt_image_yuv422:
		{
			int uneven = *width % 2;
			int count = ( *width - uneven ) / 2 + 1;
			uint8_t y, u, v;

			RGB2YUV_601_SCALED( color.r, color.g, color.b, y, u, v );
			i = *height + 1;
			while ( --i )
			{
				int j = count;
				while ( --j )
				{
					*p ++ = y;
					*p ++ = u;
					*p ++ = y;
					*p ++ = v;
				}
				if ( uneven )
				{
					*p ++ = y;
					*p ++ = u;
				}
			}
			mlt_properties_set_int( properties, "colorspace", 601 );
			break;
		}
		case mlt_image_rgb24:
			while ( --i )
			{
				*p ++ = color.r;
				*p ++ = color.g;
				*p ++ = color.b;
			}
			break;
		case mlt_image_glsl:
		case mlt_image_glsl_texture:
			memset(p, 0, size);
			break;
		case mlt_image_rgb24a:
			while ( --i )
			{
				*p ++ = color.r;
				*p ++ = color.g;
				*p ++ = color.b;
				*p ++ = color.a;
			}
			break;
		default:
			mlt_log_error( MLT_PRODUCER_SERVICE( producer ),
				"invalid image format %s\n", mlt_image_format_name( *format ) );
		}
	}
	else
	{
		mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) );
	}

	// Create the alpha channel
	int alpha_size = 0;
	uint8_t *alpha = NULL;

	// Initialise the alpha
	if (color.a < 255 || *format == mlt_image_rgb24a) {
		alpha_size = *width * *height;
		alpha = mlt_pool_alloc( alpha_size );
		if ( alpha )
			memset( alpha, color.a, alpha_size );
		else
			alpha_size = 0;
	}

	// Clone our image
	if (buffer && image && size > 0) {
		*buffer = mlt_pool_alloc( size );
		memcpy( *buffer, image, size );
	}

	// Now update properties so we free the copy after
	mlt_frame_set_image( frame, *buffer, size, mlt_pool_release );
	mlt_frame_set_alpha( frame, alpha, alpha_size, mlt_pool_release );
	mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( producer_props, "aspect_ratio" ) );
	mlt_properties_set_int( properties, "meta.media.width", *width );
	mlt_properties_set_int( properties, "meta.media.height", *height );


	return 0;
}
Ejemplo n.º 28
0
int mlt_consumer_start( mlt_consumer self )
{
	if ( !mlt_consumer_is_stopped( self ) )
		return 0;

	// Stop listening to the property-changed event
	mlt_event_block( self->event_listener );

	// Get the properies
	mlt_properties properties = MLT_CONSUMER_PROPERTIES( self );

	// Determine if there's a test card producer
	char *test_card = mlt_properties_get( properties, "test_card" );

	// Just to make sure nothing is hanging around...
	pthread_mutex_lock( &self->put_mutex );
	self->put = NULL;
	self->put_active = 1;
	pthread_mutex_unlock( &self->put_mutex );

	// Deal with it now.
	if ( test_card != NULL )
	{
		if ( mlt_properties_get_data( properties, "test_card_producer", NULL ) == NULL )
		{
			// Create a test card producer
			mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) );
			mlt_producer producer = mlt_factory_producer( profile, NULL, test_card );

			// Do we have a producer
			if ( producer != NULL )
			{
				// Test card should loop I guess...
				mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer ), "eof", "loop" );
				//mlt_producer_set_speed( producer, 0 );
				//mlt_producer_set_in_and_out( producer, 0, 0 );

				// Set the test card on the consumer
				mlt_properties_set_data( properties, "test_card_producer", producer, 0, ( mlt_destructor )mlt_producer_close, NULL );
			}
		}
	}
	else
	{
		// Allow the hash table to speed things up
		mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL );
	}

	// The profile could have changed between a stop and a restart.
	apply_profile_properties( self, mlt_service_profile( MLT_CONSUMER_SERVICE(self) ), properties );

	// Set the frame duration in microseconds for the frame-dropping heuristic
	int frame_rate_num = mlt_properties_get_int( properties, "frame_rate_num" );
	int frame_rate_den = mlt_properties_get_int( properties, "frame_rate_den" );
	int frame_duration = 0;

	if ( frame_rate_num && frame_rate_den )
	{
		frame_duration = 1000000 / frame_rate_num * frame_rate_den;
	}

	mlt_properties_set_int( properties, "frame_duration", frame_duration );

	// Check and run an ante command
	if ( mlt_properties_get( properties, "ante" ) )
		if ( system( mlt_properties_get( properties, "ante" ) ) == -1 )
			mlt_log( MLT_CONSUMER_SERVICE( self ), MLT_LOG_ERROR, "system(%s) failed!\n", mlt_properties_get( properties, "ante" ) );

	// Set the real_time preference
	self->real_time = mlt_properties_get_int( properties, "real_time" );

	// For worker threads implementation, buffer must be at least # threads
	if ( abs( self->real_time ) > 1 && mlt_properties_get_int( properties, "buffer" ) <= abs( self->real_time ) )
		mlt_properties_set_int( properties, "_buffer", abs( self->real_time ) + 1 );

	// Get the image format to use for rendering threads
	const char* format = mlt_properties_get( properties, "mlt_image_format" );
	if ( format )
	{
		if ( !strcmp( format, "rgb24" ) )
			self->format = mlt_image_rgb24;
		else if ( !strcmp( format, "rgb24a" ) )
			self->format = mlt_image_rgb24a;
		else if ( !strcmp( format, "yuv420p" ) )
			self->format = mlt_image_yuv420p;
		else if ( !strcmp( format, "none" ) )
			self->format = mlt_image_none;
		else
			self->format = mlt_image_yuv422;
	}

	// Start the service
	if ( self->start != NULL )
		return self->start( self );

	return 0;
}
Ejemplo n.º 29
0
static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{
	int error = 0;
	mlt_filter filter = (mlt_filter)mlt_frame_pop_service( frame );
	mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter );
	char* rect_str = mlt_properties_get( filter_properties, "rect" );
	if ( !rect_str )
	{
		mlt_log_warning( MLT_FILTER_SERVICE(filter), "rect property not set\n" );
		return mlt_frame_get_image( frame, image, format, width, height, writable );
	}
	mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) );
	mlt_position position = mlt_filter_get_position( filter, frame );
	mlt_position length = mlt_filter_get_length2( filter, frame );
	mlt_rect rect = mlt_properties_anim_get_rect( filter_properties, "rect", position, length );
	if ( strchr( rect_str, '%' ) )
	{
		rect.x *= profile->width;
		rect.w *= profile->width;
		rect.y *= profile->height;
		rect.h *= profile->height;
	}
	rect = constrain_rect( rect, profile->width, profile->height );
	if ( rect.w < 1 || rect.h < 1 )
	{
		mlt_log_info( MLT_FILTER_SERVICE(filter), "rect invalid\n" );
		return mlt_frame_get_image( frame, image, format, width, height, writable );
	}

	switch( *format )
	{
		case mlt_image_rgb24a:
		case mlt_image_rgb24:
		case mlt_image_yuv422:
		case mlt_image_yuv420p:
			// These formats are all supported
			break;
		default:
			*format = mlt_image_rgb24a;
			break;
	}
	error = mlt_frame_get_image( frame, image, format, width, height, 1 );
	if (error) return error;

	int i;
	switch( *format )
	{
		case mlt_image_rgb24a:
			for ( i = 0; i < 4; i++ )
			{
				remove_spot_channel( *image + i, *width, 4, rect );
			}
			break;
		case mlt_image_rgb24:
			for ( i = 0; i < 3; i++ )
			{
				remove_spot_channel( *image + i, *width, 3, rect );
			}
			break;
		case mlt_image_yuv422:
			// Y
			remove_spot_channel( *image, *width, 2, rect );
			// U
			remove_spot_channel( *image + 1, *width / 2, 4,
								 constrain_rect( scale_rect( rect, 2, 1 ), *width / 2, *height ) );
			// V
			remove_spot_channel( *image + 3, *width / 2, 4,
								 constrain_rect( scale_rect( rect, 2, 1 ), *width / 2, *height ) );
			break;
		case mlt_image_yuv420p:
			// Y
			remove_spot_channel( *image, *width, 1, rect );
			// U
			remove_spot_channel( *image + (*width * *height), *width / 2, 1,
								 constrain_rect( scale_rect( rect, 2, 2 ), *width / 2, *height / 2 ) );
			// V
			remove_spot_channel( *image + (*width * *height * 5 / 4), *width / 2, 1,
								 constrain_rect( scale_rect( rect, 2, 2 ), *width / 2, *height / 2 ) );
			break;
		default:
			return 1;
	}

	uint8_t *alpha = mlt_frame_get_alpha( frame );
	if ( alpha && *format != mlt_image_rgb24a )
	{
		remove_spot_channel( alpha, *width, 1, rect );
	}

	return error;
}
Ejemplo n.º 30
0
static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{
	// Get the b frame from the stack
	mlt_frame b_frame = mlt_frame_pop_frame( a_frame );

	// Get the transition object
	mlt_transition transition = mlt_frame_pop_service( a_frame );

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

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

	// Get the properties of the b frame
	mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame );

	// Image, format, width, height and image for the b frame
	uint8_t *b_image = NULL;
	mlt_image_format b_format = mlt_image_rgb24a;
	int b_width;
	int b_height;

	// Assign the current position
	mlt_position position =  mlt_transition_get_position( transition, a_frame );

	int mirror = mlt_properties_get_position( properties, "mirror" );
	int length = mlt_transition_get_length( transition );
	if ( mlt_properties_get_int( properties, "always_active" ) )
	{
		mlt_properties props = mlt_properties_get_data( b_props, "_producer", NULL );
		mlt_position in = mlt_properties_get_int( props, "in" );
		mlt_position out = mlt_properties_get_int( props, "out" );
		length = out - in + 1;
	}

	// Obtain the normalised width and height from the a_frame
	mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( transition ) );
	int normalised_width = profile->width;
	int normalised_height = profile->height;

	double consumer_ar = mlt_profile_sar( mlt_service_profile( MLT_TRANSITION_SERVICE(transition) ) );

	// Structures for geometry
	struct mlt_geometry_item_s result;

	if ( mirror && position > length / 2 )
		position = abs( position - length );

	// Fetch the a frame image
	*format = mlt_image_rgb24a;
	mlt_frame_get_image( a_frame, image, format, width, height, 1 );

	// Calculate the region now
	mlt_service_lock( MLT_TRANSITION_SERVICE( transition ) );
	composite_calculate( transition, &result, normalised_width, normalised_height, ( float )position );
	mlt_service_unlock( MLT_TRANSITION_SERVICE( transition ) );

	// Fetch the b frame image
	result.w = ( result.w * *width / normalised_width );
	result.h = ( result.h * *height / normalised_height );
	result.x = ( result.x * *width / normalised_width );
	result.y = ( result.y * *height / normalised_height );

	// Request full resolution of b frame image.
	b_width = mlt_properties_get_int( b_props, "meta.media.width" );
	b_height = mlt_properties_get_int( b_props, "meta.media.height" );
	mlt_properties_set_int( b_props, "rescale_width", b_width );
	mlt_properties_set_int( b_props, "rescale_height", b_height );

	// Suppress padding and aspect normalization.
	char *interps = mlt_properties_get( a_props, "rescale.interp" );
	if ( interps )
		interps = strdup( interps );
	mlt_properties_set( b_props, "rescale.interp", "none" );

	// This is not a field-aware transform.
	mlt_properties_set_int( b_props, "consumer_deinterlace", 1 );

	mlt_frame_get_image( b_frame, &b_image, &b_format, &b_width, &b_height, 0 );

	// Check that both images are of the correct format and process
	if ( *format == mlt_image_rgb24a && b_format == mlt_image_rgb24a )
	{
		float x, y;
		float dx, dy;
		float dz;
		float sw, sh;
		uint8_t *p = *image;

		// Get values from the transition
		float scale_x = mlt_properties_get_double( properties, "scale_x" );
		float scale_y = mlt_properties_get_double( properties, "scale_y" );
		int scale = mlt_properties_get_int( properties, "scale" );
		int b_alpha = mlt_properties_get_int( properties, "b_alpha" );
		float geom_scale_x = (float) b_width / result.w;
		float geom_scale_y = (float) b_height / result.h;
		float cx = result.x + result.w / 2.0;
		float cy = result.y + result.h / 2.0;
		float lower_x = - cx;
		float lower_y = - cy;
		float x_offset = (float) b_width / 2.0;
		float y_offset = (float) b_height / 2.0;
		affine_t affine;
		interpp interp = interpBL_b32;
		int i, j; // loop counters

		affine_init( affine.matrix );

		// Compute the affine transform
		get_affine( &affine, transition, ( float )position );
		dz = MapZ( affine.matrix, 0, 0 );
		if ( ( int )abs( dz * 1000 ) < 25 )
		{
			if ( interps )
				free( interps );
			return 0;
		}

		// Factor scaling into the transformation based on output resolution.
		if ( mlt_properties_get_int( properties, "distort" ) )
		{
			scale_x = geom_scale_x * ( scale_x == 0 ? 1 : scale_x );
			scale_y = geom_scale_y * ( scale_y == 0 ? 1 : scale_y );
		}
		else
		{
			// Determine scale with respect to aspect ratio.
			double consumer_dar = consumer_ar * normalised_width / normalised_height;
			double b_ar = mlt_properties_get_double( b_props, "aspect_ratio" );
			double b_dar = b_ar * b_width / b_height;
			
			if ( b_dar > consumer_dar )
			{
				scale_x = geom_scale_x * ( scale_x == 0 ? 1 : scale_x );
				scale_y = geom_scale_x * ( scale_y == 0 ? 1 : scale_y );
			}
			else
			{
				scale_x = geom_scale_y * ( scale_x == 0 ? 1 : scale_x );
				scale_y = geom_scale_y * ( scale_y == 0 ? 1 : scale_y );
			}
			scale_x *= consumer_ar / b_ar;
		}
		if ( scale )
		{
			affine_max_output( affine.matrix, &sw, &sh, dz, *width, *height );
			affine_scale( affine.matrix, sw * MIN( geom_scale_x, geom_scale_y ), sh * MIN( geom_scale_x, geom_scale_y ) );
		}
		else if ( scale_x != 0 && scale_y != 0 )
		{
			affine_scale( affine.matrix, scale_x, scale_y );
		}

		// Set the interpolation function
		if ( interps == NULL || strcmp( interps, "nearest" ) == 0 || strcmp( interps, "neighbor" ) == 0 )
			interp = interpNN_b32;
		else if ( strcmp( interps, "tiles" ) == 0 || strcmp( interps, "fast_bilinear" ) == 0 )
			interp = interpNN_b32;
		else if ( strcmp( interps, "bilinear" ) == 0 )
			interp = interpBL_b32;
		else if ( strcmp( interps, "bicubic" ) == 0 )
			interp = interpBC_b32;
		 // TODO: lanczos 8x8
		else if ( strcmp( interps, "hyper" ) == 0 || strcmp( interps, "sinc" ) == 0 || strcmp( interps, "lanczos" ) == 0 )
			interp = interpBC_b32;
		else if ( strcmp( interps, "spline" ) == 0 ) // TODO: spline 4x4 or 6x6
			interp = interpBC_b32;

		// Do the transform with interpolation
		for ( i = 0, y = lower_y; i < *height; i++, y++ )
		{
			for ( j = 0, x = lower_x; j < *width; j++, x++ )
			{
				dx = MapX( affine.matrix, x, y ) / dz + x_offset;
				dy = MapY( affine.matrix, x, y ) / dz + y_offset;
				if ( dx >= 0 && dx < (b_width - 1) && dy >=0 && dy < (b_height - 1) )
					interp( b_image, b_width, b_height, dx, dy, result.mix/100.0, p, b_alpha );
				p += 4;
			}
		}
	}
	if ( interps )
		free( interps );

	return 0;
}