Пример #1
0
static inline void get_affine( affine_t *affine, mlt_transition transition, double position, int length )
{
	mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition );
	int keyed = mlt_properties_get_int( properties, "keyed" );

	if ( keyed == 0 )
	{
		double fix_rotate_x = anim_get_angle( properties, "fix_rotate_x", position, length );
		double fix_rotate_y = anim_get_angle( properties, "fix_rotate_y", position, length );
		double fix_rotate_z = anim_get_angle( properties, "fix_rotate_z", position, length );
		double rotate_x = mlt_properties_get_double( properties, "rotate_x" );
		double rotate_y = mlt_properties_get_double( properties, "rotate_y" );
		double rotate_z = mlt_properties_get_double( properties, "rotate_z" );
		double fix_shear_x = anim_get_angle( properties, "fix_shear_x", position, length );
		double fix_shear_y = anim_get_angle( properties, "fix_shear_y", position, length );
		double fix_shear_z = anim_get_angle( properties, "fix_shear_z", position, length );
		double shear_x = mlt_properties_get_double( properties, "shear_x" );
		double shear_y = mlt_properties_get_double( properties, "shear_y" );
		double shear_z = mlt_properties_get_double( properties, "shear_z" );
		double ox = mlt_properties_anim_get_double( properties, "ox", position, length );
		double oy = mlt_properties_anim_get_double( properties, "oy", position, length );

		affine_rotate_x( affine->matrix, fix_rotate_x + rotate_x * position );
		affine_rotate_y( affine->matrix, fix_rotate_y + rotate_y * position );
		affine_rotate_z( affine->matrix, fix_rotate_z + rotate_z * position );
		affine_shear( affine->matrix,
					  fix_shear_x + shear_x * position,
					  fix_shear_y + shear_y * position,
					  fix_shear_z + shear_z * position );
		affine_offset( affine->matrix, ox, oy );
	}
	else
	{
		double rotate_x = anim_get_angle(properties, "rotate_x", position, length);
		double rotate_y = anim_get_angle(properties, "rotate_y", position, length);
		double rotate_z = anim_get_angle(properties, "rotate_z", position, length);
		double shear_x = anim_get_angle(properties, "shear_x", position, length);
		double shear_y = anim_get_angle(properties, "shear_y", position, length);
		double shear_z = anim_get_angle(properties, "shear_z", position, length);
		double o_x = mlt_properties_anim_get_double(properties, "ox",
			repeat_position(properties, "ox", position, length), length);
		double o_y = mlt_properties_anim_get_double(properties, "oy",
			repeat_position(properties, "oy", position, length), length);
		
		affine_rotate_x( affine->matrix, rotate_x );
		affine_rotate_y( affine->matrix, rotate_y );
		affine_rotate_z( affine->matrix, rotate_z );
		affine_shear( affine->matrix, shear_x, shear_y, shear_z );
		affine_offset( affine->matrix, o_x, o_y );
	}
}
Пример #2
0
static double anim_get_angle(mlt_properties properties, const char* name, mlt_position position, mlt_position length)
{
	double result = 0.0;
	if (mlt_properties_get(properties, name)) {
		position = repeat_position(properties, name, position, length);
		result = mlt_properties_anim_get_double(properties, name, position, length);
		if (strchr(mlt_properties_get(properties, name), '%'))
			result *= 360;
	}
	return result;
}
Пример #3
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 );

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

	if ( error == 0 && *image )
	{
		int h = *height;
		int w = *width;

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

		int noise = mlt_properties_anim_get_int( properties, "noise", pos, len );
		double contrast = mlt_properties_anim_get_double( properties, "contrast", pos, len ) / 100.0;
		double brightness = 127.0 * (mlt_properties_anim_get_double( properties, "brightness", pos, len ) -100.0 ) / 100.0;
		
		int x = 0,y = 0,pix = 0;
		for ( x = 0; x < w; x++ )
		{
			for( y = 0; y < h; y++ )
			{
				uint8_t* pixel = (*image + (y) * w * 2 + (x) * 2 );
				if (*pixel > 20)
				{
					pix = MIN ( MAX ( ( (double)*pixel -127.0  ) * contrast + 127.0 + brightness , 0 ) , 255 ) ;
					if ( noise > 0 ) pix -= ( rand() % noise - noise );

					*pixel = MIN ( MAX ( pix , 0 ) , 255 );
				}
			}
		}
	}

	return error;
}
Пример #4
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 position = mlt_filter_get_position( filter, frame );
	mlt_position length = mlt_filter_get_length2( filter, frame );

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

	// Only process if we have no error and a valid colour space
	if ( error == 0 )
	{
		double level = 1.0;

		// Use animated "level" property only if it has been set since init
		char* level_property = mlt_properties_get( MLT_FILTER_PROPERTIES( filter ), "level" );
		if ( level_property != NULL )
		{
			level = mlt_properties_anim_get_double( properties, "level", position, length );
		}
		else
		{
			// Get level using old "start,"end" mechanics
			// Get the starting brightness level
			level = fabs( mlt_properties_get_double( MLT_FILTER_PROPERTIES( filter ), "start" ) );

			// If there is an end adjust gain to the range
			if ( mlt_properties_get( MLT_FILTER_PROPERTIES( filter ), "end" ) != NULL )
			{
				// Determine the time position of this frame in the transition duration
				double end = fabs( mlt_properties_get_double( MLT_FILTER_PROPERTIES( filter ), "end" ) );
				level += ( end - level ) * mlt_filter_get_progress( filter, frame );
			}
		}

		// Only process if level is something other than 1
		if ( level != 1.0 )
		{
			int i = *width * *height + 1;
			uint8_t *p = *image;
			int32_t m = level * ( 1 << 16 );
			int32_t n = 128 * ( ( 1 << 16 ) - m );

			while ( --i )
			{
				p[0] = CLAMP( (p[0] * m) >> 16, 16, 235 );
				p[1] = CLAMP( (p[1] * m + n) >> 16, 16, 240 );
				p += 2;
			}
		}
Пример #5
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 position = mlt_frame_get_position( frame );

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

	// Only process if we have no error and a valid colour space
	if ( error == 0 )
	{
		double factor = mlt_properties_get_double( properties, "start" );

		mlt_position f_pos = mlt_filter_get_position( filter, frame );
		mlt_position f_len = mlt_filter_get_length2( filter, frame );
		int speed = mlt_properties_anim_get_int( properties, "speed", f_pos, f_len );
		int deformX = mlt_properties_anim_get_int( properties, "deformX", f_pos, f_len );
		int deformY = mlt_properties_anim_get_int( properties, "deformY", f_pos, f_len );

		if ( mlt_properties_get( properties, "end" ) )
		{
			// Determine the time position of this frame in the transition duration
			double end = fabs( mlt_properties_get_double( MLT_FILTER_PROPERTIES( filter ), "end" ) );
			factor += ( end - factor ) * mlt_filter_get_progress( filter, frame );
		}

		// If animated property "wave" is set, use its value. 
		char* wave_property = mlt_properties_get( properties, "wave" );
		if ( wave_property )
		{
			factor = mlt_properties_anim_get_double( properties, "wave", f_pos, f_len );
		}

		if (factor != 0) 
		{
			int image_size = *width * (*height) * 2;
			uint8_t *dst = mlt_pool_alloc (image_size);
			DoWave(*image, *width, (*height), dst, position, speed, factor, deformX, deformY);
			*image = dst;
			mlt_frame_set_image( frame, *image, image_size, mlt_pool_release );
		}
	}

	return error;
}
Пример #6
0
static mlt_position repeat_position(mlt_properties properties, const char* name, mlt_position position, int length)
{
	// Make mlt_properties parse and refresh animation.
	mlt_properties_anim_get_double(properties, name, position, length);
	mlt_animation animation = mlt_properties_get_animation(properties, name);
	if (animation) {
		// Apply repeat and mirror options.
		int anim_length = mlt_animation_get_length(animation);
		int repeat_off = mlt_properties_get_int(properties, "repeat_off");
		if (!repeat_off && position >= anim_length && anim_length != 0) {
			int section = position / anim_length;
			int mirror_off = mlt_properties_get_int(properties, "mirror_off");
			position -= section * anim_length;
			if (!mirror_off && section % 2 == 1)
				position = anim_length - position;
		}
	}
	return position;
}
Пример #7
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 position = mlt_filter_get_position( filter, frame );
	mlt_position length = mlt_filter_get_length2( filter, frame );

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

	if ( error == 0 )
	{
		// Get the gamma value
		double gamma = mlt_properties_anim_get_double( properties, "gamma", position, length );

		if ( gamma != 1.0 )
		{
			uint8_t *p = *image;
			uint8_t *q = *image + *width * *height * 2;

			// Calculate the look up table
			double exp = 1 / gamma;
			uint8_t lookup[ 256 ];
			int i;

			for( i = 0; i < 256; i ++ )
				lookup[ i ] = ( uint8_t )( pow( ( double )i / 255.0, exp ) * 255 );

			while ( p != q )
			{
				*p = lookup[ *p ];
				p += 2;
			}
		}
	}

	return 0;
}
Пример #8
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 position = mlt_filter_get_position( filter, frame );
	mlt_position length = mlt_filter_get_length2( filter, frame );
	double level = 1.0;

	// Use animated "level" property only if it has been set since init
	char* level_property = mlt_properties_get( properties, "level" );
	if ( level_property != NULL )
	{
		level = mlt_properties_anim_get_double( properties, "level", position, length );
	}
	else
	{
		// Get level using old "start,"end" mechanics
		// Get the starting brightness level
		level = fabs( mlt_properties_get_double( properties, "start" ) );

		// If there is an end adjust gain to the range
		if ( mlt_properties_get( properties, "end" ) != NULL )
		{
			// Determine the time position of this frame in the transition duration
			double end = fabs( mlt_properties_get_double( properties, "end" ) );
			level += ( end - level ) * mlt_filter_get_progress( filter, frame );
		}
	}

	// Do not cause an image conversion unless there is real work to do.
	if ( level != 1.0 )
		*format = mlt_image_yuv422;

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

	// Only process if we have no error.
	if ( error == 0 )
	{
		// Only process if level is something other than 1
		if ( level != 1.0 && *format == mlt_image_yuv422 )
		{
			int i = *width * *height + 1;
			uint8_t *p = *image;
			int32_t m = level * ( 1 << 16 );
			int32_t n = 128 * ( ( 1 << 16 ) - m );

			while ( --i )
			{
				p[0] = CLAMP( (p[0] * m) >> 16, 16, 235 );
				p[1] = CLAMP( (p[1] * m + n) >> 16, 16, 240 );
				p += 2;
			}
		}

		// Process the alpha channel if requested.
		if ( mlt_properties_get( properties, "alpha" ) )
		{
			double alpha = mlt_properties_anim_get_double( properties, "alpha", position, length );
			alpha = alpha >= 0.0 ? alpha : level;
			if ( alpha != 1.0 )
			{
				int32_t m = alpha * ( 1 << 16 );
				int i = *width * *height + 1;

				if ( *format == mlt_image_rgb24a ) {
					uint8_t *p = *image + 3;
					for ( ; --i; p += 4 )
						p[0] = ( p[0] * m ) >> 16;
				} else {
Пример #9
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;
}
Пример #10
0
static mlt_frame filter_process( mlt_filter filter, mlt_frame frame )
{
	mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
	mlt_properties frame_props = MLT_FRAME_PROPERTIES( frame );
	mlt_properties instance_props = mlt_properties_new();

	// Only if mix is specified, otherwise a producer may set the mix
	if ( mlt_properties_get( properties, "start" ) != NULL )
	{
		// Determine the time position of this frame in the filter duration
		mlt_properties props = mlt_properties_get_data( frame_props, "_producer", NULL );
		int always_active = mlt_properties_get_int(  properties, "always_active" );
		mlt_position in = !always_active ? mlt_filter_get_in( filter ) : mlt_properties_get_int( props, "in" );
		mlt_position out = !always_active ? mlt_filter_get_out( filter ) : mlt_properties_get_int( props, "out" );
		int length = mlt_properties_get_int(  properties, "length" );
		mlt_position time = !always_active ? mlt_frame_get_position( frame ) : mlt_properties_get_int( props, "_frame" );
		double mix = ( double )( time - in ) / ( double )( out - in + 1 );

		if ( length == 0 )
		{
			// If there is an end mix level adjust mix to the range
			if ( mlt_properties_get( properties, "end" ) != NULL )
			{
				double start = mlt_properties_get_double( properties, "start" );
				double end = mlt_properties_get_double( properties, "end" );
				mix = start + ( end - start ) * mix;
			}
			// Use constant mix level if only start
			else if ( mlt_properties_get( properties, "start" ) != NULL )
			{
				mix = mlt_properties_get_double( properties, "start" );
			}

			// Use animated property "split" to get mix level if property is set
			char* split_property = mlt_properties_get( properties, "split" );
			if ( split_property )
			{
				mlt_position pos = mlt_filter_get_position( filter, frame );
				mlt_position len = mlt_filter_get_length2( filter, frame );
				mix = mlt_properties_anim_get_double( properties, "split", pos, len );
			}

			// Convert it from [0, 1] to [-1, 1]
			mix = mix * 2.0 - 1.0;
		
			// Finally, set the mix property on the frame
			mlt_properties_set_double( instance_props, "mix", mix );
	
			// Initialise filter previous mix value to prevent an inadvertant jump from 0
			mlt_position last_position = mlt_properties_get_position( properties, "_last_position" );
			mlt_position current_position = mlt_frame_get_position( frame );
			mlt_properties_set_position( properties, "_last_position", current_position );
			if ( mlt_properties_get( properties, "_previous_mix" ) == NULL
				 || current_position != last_position + 1 )
				mlt_properties_set_double( properties, "_previous_mix", mix );
				
			// Tell the frame what the previous mix level was
			mlt_properties_set_double( instance_props, "previous_mix", mlt_properties_get_double( properties, "_previous_mix" ) );

			// Save the current mix level for the next iteration
			mlt_properties_set_double( properties, "_previous_mix", mix );
		}
		else
		{
			double level = mlt_properties_get_double( properties, "start" );
			double mix_start = level;
			double mix_end = mix_start;
			double mix_increment = 1.0 / length;
			if ( time - in < length )
			{
				mix_start *= ( double )( time - in ) / length;
				mix_end = mix_start + mix_increment;
			}
			else if ( time > out - length )
			{
				mix_end = mix_start * ( ( double )( out - time - in ) / length );
				mix_start = mix_end - mix_increment;
			}

			mix_start = mix_start < 0 ? 0 : mix_start > level ? level : mix_start;
			mix_end = mix_end < 0 ? 0 : mix_end > level ? level : mix_end;
			mlt_properties_set_double( instance_props, "previous_mix", mix_start );
			mlt_properties_set_double( instance_props, "mix", mix_end );
		}
		mlt_properties_set_int( instance_props, "channel", mlt_properties_get_int( properties, "channel" ) );
		mlt_properties_set_int( instance_props, "gang", mlt_properties_get_int( properties, "gang" ) );
	}
	mlt_properties_set_data( frame_props, mlt_properties_get( properties, "_unique_id" ),
		instance_props, 0, (mlt_destructor) mlt_properties_close, NULL );

	// Override the get_audio method
	mlt_frame_push_audio( frame, filter );
	mlt_frame_push_audio( frame, instance_props );
	mlt_frame_push_audio( frame, filter_get_audio );
	
	return frame;
}
Пример #11
0
 double getNumberParameter(const QString& name) {
     return mlt_properties_anim_get_double(properties, name.toLatin1().constData(), position, length);
 }
Пример #12
0
static int ladspa_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
{
	int error = 0;

	// Get the filter service
	mlt_filter filter = mlt_frame_pop_audio( frame );

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

	// Initialise LADSPA if needed
	jack_rack_t *jackrack = mlt_properties_get_data( filter_properties, "jackrack", NULL );
	if ( jackrack == NULL )
	{
		sample_rate = *frequency; // global inside jack_rack
		jackrack = initialise_jack_rack( filter_properties, *channels );
	}

	if ( jackrack && jackrack->procinfo && jackrack->procinfo->chain &&
		 mlt_properties_get_int64( filter_properties, "_pluginid" ) )
	{
		plugin_t *plugin = jackrack->procinfo->chain;
		LADSPA_Data value;
		int i, c;
		mlt_position position = mlt_filter_get_position( filter, frame );
		mlt_position length = mlt_filter_get_length2( filter, frame );

		// Get the producer's audio
		*channels = jackrack->channels;
		*format = mlt_audio_float;
		mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples );

		for ( i = 0; i < plugin->desc->control_port_count; i++ )
		{
			// Apply the control port values
			char key[20];
			value = plugin_desc_get_default_control_value( plugin->desc, i, sample_rate );
			snprintf( key, sizeof(key), "%d", i );
			if ( mlt_properties_get( filter_properties, key ) )
				value = mlt_properties_anim_get_double( filter_properties, key, position, length );
			for ( c = 0; c < plugin->copies; c++ )
				plugin->holders[c].control_memory[i] = value;
		}
		plugin->wet_dry_enabled = mlt_properties_get( filter_properties, "wetness" ) != NULL;
		if ( plugin->wet_dry_enabled )
		{
			value = mlt_properties_anim_get_double( filter_properties, "wetness", position, length );
			for ( c = 0; c < *channels; c++ )
				plugin->wet_dry_values[c] = value;
		}

		// Configure the buffers
		LADSPA_Data **input_buffers  = mlt_pool_alloc( sizeof( LADSPA_Data* ) * *channels );
		LADSPA_Data **output_buffers = mlt_pool_alloc( sizeof( LADSPA_Data* ) * *channels );

		for ( i = 0; i < *channels; i++ )
		{
			input_buffers[i]  = (LADSPA_Data*) *buffer + i * *samples;
			output_buffers[i] = (LADSPA_Data*) *buffer + i * *samples;
		}

		// Do LADSPA processing
		error = process_ladspa( jackrack->procinfo, *samples, input_buffers, output_buffers );

		mlt_pool_release( input_buffers );
		mlt_pool_release( output_buffers );

		// read the status port values
		for ( i = 0; i < plugin->desc->status_port_count; i++ )
		{
			char key[20];
			int p = plugin->desc->status_port_indicies[i];
			for ( c = 0; c < plugin->copies; c++ )
			{
				snprintf( key, sizeof(key), "%d[%d]", p, c );
				value = plugin->holders[c].status_memory[i];
				mlt_properties_set_double( filter_properties, key, value );
			}
		}
	}
	else
	{
		// Nothing to do.
		error = mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples );
	}

	return error;
}
Пример #13
0
static void refresh_lut( mlt_filter filter, mlt_frame frame )
{
	private_data* self = (private_data*)filter->child;
	mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
	mlt_position position = mlt_filter_get_position( filter, frame );
	mlt_position length = mlt_filter_get_length2( filter, frame );
	double rlift = mlt_properties_anim_get_double( properties, "lift_r", position, length );
	double glift = mlt_properties_anim_get_double( properties, "lift_g", position, length );
	double blift = mlt_properties_anim_get_double( properties, "lift_b", position, length );
	double rgamma = mlt_properties_anim_get_double( properties, "gamma_r", position, length );
	double ggamma = mlt_properties_anim_get_double( properties, "gamma_g", position, length );
	double bgamma = mlt_properties_anim_get_double( properties, "gamma_b", position, length );
	double rgain = mlt_properties_anim_get_double( properties, "gain_r", position, length );
	double ggain = mlt_properties_anim_get_double( properties, "gain_g", position, length );
	double bgain = mlt_properties_anim_get_double( properties, "gain_b", position, length );

	// Only regenerate the LUT if something changed.
	if( self->rlift != rlift || self->glift != glift || self->blift != blift ||
		self->rgamma != rgamma || self->ggamma != ggamma || self->bgamma != bgamma ||
		self->rgain != rgain || self->ggain != ggain || self->bgain != bgain )
	{
		int i = 0;
		for( i = 0; i < 256; i++ )
		{
			// Convert to gamma 2.2
			double gamma22 = pow( (double)i / 255.0, 1.0 / 2.2 );
			double r = gamma22;
			double g = gamma22;
			double b = gamma22;

			// Apply lift
			r += rlift * ( 1.0 - r );
			g += glift * ( 1.0 - g );
			b += blift * ( 1.0 - b );

			// Clamp negative values
			r = MAX( r, 0.0 );
			g = MAX( g, 0.0 );
			b = MAX( b, 0.0 );

			// Apply gamma
			r = pow( r, 2.2 / rgamma );
			g = pow( g, 2.2 / ggamma );
			b = pow( b, 2.2 / bgamma );

			// Apply gain
			r *= pow( rgain, 1.0 / rgamma );
			g *= pow( ggain, 1.0 / ggamma );
			b *= pow( bgain, 1.0 / bgamma );

			// Clamp values
			r = CLAMP( r, 0.0, 1.0 );
			g = CLAMP( g, 0.0, 1.0 );
			b = CLAMP( b, 0.0, 1.0 );

			// Update LUT
			self->rlut[ i ] = (int)(r * 255.0);
			self->glut[ i ] = (int)(g * 255.0);
			self->blut[ i ] = (int)(b * 255.0);
		}

		// Store the values that created the LUT so that
		// changes can be detected.
		self->rlift = rlift;
		self->glift = glift;
		self->blift = blift;
		self->rgamma = rgamma;
		self->ggamma = ggamma;
		self->bgamma = bgamma;
		self->rgain = rgain;
		self->ggain = ggain;
		self->bgain = bgain;
	}
}
Пример #14
0
static int ladspa_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
{
	int error = 0;

	// Get the filter service
	mlt_filter filter = mlt_frame_pop_audio( frame );

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

	// Check if the channel configuration has changed
	int prev_channels = mlt_properties_get_int( filter_properties, "_prev_channels" );
	if ( prev_channels != *channels )
	{
		if( prev_channels )
		{
			mlt_log_info( MLT_FILTER_SERVICE(filter), "Channel configuration changed. Old: %d New: %d.\n", prev_channels, *channels );
			mlt_properties_set_data( filter_properties, "jackrack", NULL, 0, (mlt_destructor) NULL, NULL );
		}
		mlt_properties_set_int( filter_properties, "_prev_channels", *channels );
	}

	// Initialise LADSPA if needed
	jack_rack_t *jackrack = mlt_properties_get_data( filter_properties, "jackrack", NULL );
	if ( jackrack == NULL )
	{
		sample_rate = *frequency; // global inside jack_rack
		jackrack = initialise_jack_rack( filter_properties, *channels );
	}

	if ( jackrack && jackrack->procinfo && jackrack->procinfo->chain &&
		 mlt_properties_get_int64( filter_properties, "_pluginid" ) )
	{
		plugin_t *plugin = jackrack->procinfo->chain;
		LADSPA_Data value;
		int i, c;
		mlt_position position = mlt_filter_get_position( filter, frame );
		mlt_position length = mlt_filter_get_length2( filter, frame );

		// Get the producer's audio
		*format = mlt_audio_float;
		mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples );

		// Resize the buffer if necessary.
		if ( *channels < jackrack->channels )
		{
			// Add extra channels to satisfy the plugin.
			// Extra channels in the buffer will be ignored by downstream services.
			int old_size = mlt_audio_format_size( *format, *samples, *channels );
			int new_size = mlt_audio_format_size( *format, *samples, jackrack->channels );
			uint8_t* new_buffer = mlt_pool_alloc( new_size );
			memcpy( new_buffer, *buffer, old_size );
			// Put silence in extra channels.
			memset( new_buffer + old_size, 0, new_size - old_size );
			mlt_frame_set_audio( frame, new_buffer, *format, new_size, mlt_pool_release );
			*buffer = new_buffer;
		}

		for ( i = 0; i < plugin->desc->control_port_count; i++ )
		{
			// Apply the control port values
			char key[20];
			value = plugin_desc_get_default_control_value( plugin->desc, i, sample_rate );
			snprintf( key, sizeof(key), "%d", i );
			if ( mlt_properties_get( filter_properties, key ) )
				value = mlt_properties_anim_get_double( filter_properties, key, position, length );
			for ( c = 0; c < plugin->copies; c++ )
				plugin->holders[c].control_memory[i] = value;
		}
		plugin->wet_dry_enabled = mlt_properties_get( filter_properties, "wetness" ) != NULL;
		if ( plugin->wet_dry_enabled )
		{
			value = mlt_properties_anim_get_double( filter_properties, "wetness", position, length );
			for ( c = 0; c < jackrack->channels; c++ )
				plugin->wet_dry_values[c] = value;
		}

		// Configure the buffers
		LADSPA_Data **input_buffers  = mlt_pool_alloc( sizeof( LADSPA_Data* ) * jackrack->channels );
		LADSPA_Data **output_buffers = mlt_pool_alloc( sizeof( LADSPA_Data* ) * jackrack->channels );
		
		// Some plugins crash with too many frames (samples).
		// So, feed the plugin with N samples per loop iteration.
		int samples_offset = 0;
		int sample_count = MIN(*samples, MAX_SAMPLE_COUNT);
		for (i = 0; samples_offset < *samples; i++) {
			int j = 0;
			for (; j < jackrack->channels; j++)
				output_buffers[j] = input_buffers[j] = (LADSPA_Data*) *buffer + j * (*samples) + samples_offset;
			sample_count = MIN(*samples - samples_offset, MAX_SAMPLE_COUNT);
			// Do LADSPA processing
			error = process_ladspa( jackrack->procinfo, sample_count, input_buffers, output_buffers );
			samples_offset += MAX_SAMPLE_COUNT;
		}

		mlt_pool_release( input_buffers );
		mlt_pool_release( output_buffers );

		// read the status port values
		for ( i = 0; i < plugin->desc->status_port_count; i++ )
		{
			char key[20];
			int p = plugin->desc->status_port_indicies[i];
			for ( c = 0; c < plugin->copies; c++ )
			{
				snprintf( key, sizeof(key), "%d[%d]", p, c );
				value = plugin->holders[c].status_memory[i];
				mlt_properties_set_double( filter_properties, key, value );
			}
		}
	}
	else
	{
		// Nothing to do.
		error = mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples );
	}

	return error;
}
Пример #15
0
static int filter_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
{
	// Get the filter from the frame
	mlt_filter filter = mlt_frame_pop_audio( frame );

	// Get the properties from the filter
	mlt_properties filter_props = MLT_FILTER_PROPERTIES( filter );

	// Get the frame's filter instance properties
	mlt_properties instance_props = mlt_frame_unique_properties( frame, MLT_FILTER_SERVICE( filter ) );

	// Get the parameters
	double gain = mlt_properties_get_double( instance_props, "gain" );
	double max_gain = mlt_properties_get_double( instance_props, "max_gain" );
	double limiter_level = 0.5; /* -6 dBFS */
	int normalise =  mlt_properties_get_int( instance_props, "normalise" );
	double amplitude =  mlt_properties_get_double( instance_props, "amplitude" );
	int i, j;
	double sample;
	int16_t peak;
	
	// Use animated value for gain if "level" property is set 
	char* level_property = mlt_properties_get( filter_props, "level" );
	if ( level_property != NULL )
	{
		mlt_position position = mlt_filter_get_position( filter, frame );
		mlt_position length = mlt_filter_get_length2( filter, frame );
		gain = mlt_properties_anim_get_double( filter_props, "level", position, length );
		gain = DBFSTOAMP( gain );
	}

	if ( mlt_properties_get( instance_props, "limiter" ) != NULL )
		limiter_level = mlt_properties_get_double( instance_props, "limiter" );
	
	// Get the producer's audio
	*format = mlt_audio_s16;
	mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples );

	// Determine numeric limits
	int bytes_per_samp = (samp_width - 1) / 8 + 1;
	int samplemax = (1 << (bytes_per_samp * 8 - 1)) - 1;
	int samplemin = -samplemax - 1;

	mlt_service_lock( MLT_FILTER_SERVICE( filter ) );

	if ( normalise )
	{
		int window = mlt_properties_get_int( filter_props, "window" );
		double *smooth_buffer = mlt_properties_get_data( filter_props, "smooth_buffer", NULL );

		if ( window > 0 && smooth_buffer != NULL )
		{
			int smooth_index = mlt_properties_get_int( filter_props, "_smooth_index" );
			
			// Compute the signal power and put into smoothing buffer
			smooth_buffer[ smooth_index ] = signal_max_power( *buffer, *channels, *samples, &peak );

			if ( smooth_buffer[ smooth_index ] > EPSILON )
			{
				mlt_properties_set_int( filter_props, "_smooth_index", ( smooth_index + 1 ) % window );

				// Smooth the data and compute the gain
				gain *= amplitude / get_smoothed_data( smooth_buffer, window );
			}
		}
		else
		{
			gain *= amplitude / signal_max_power( (int16_t*) *buffer, *channels, *samples, &peak );
		}
	}

	if ( max_gain > 0 && gain > max_gain )
		gain = max_gain;

	// Initialise filter's previous gain value to prevent an inadvertant jump from 0
	mlt_position last_position = mlt_properties_get_position( filter_props, "_last_position" );
	mlt_position current_position = mlt_frame_get_position( frame );
	if ( mlt_properties_get( filter_props, "_previous_gain" ) == NULL
	     || current_position != last_position + 1 )
		mlt_properties_set_double( filter_props, "_previous_gain", gain );

	// Start the gain out at the previous
	double previous_gain = mlt_properties_get_double( filter_props, "_previous_gain" );

	// Determine ramp increment
	double gain_step = ( gain - previous_gain ) / *samples;

	// Save the current gain for the next iteration
	mlt_properties_set_double( filter_props, "_previous_gain", gain );
	mlt_properties_set_position( filter_props, "_last_position", current_position );

	mlt_service_unlock( MLT_FILTER_SERVICE( filter ) );

	// Ramp from the previous gain to the current
	gain = previous_gain;

	int16_t *p = (int16_t*) *buffer;

	// Apply the gain
	for ( i = 0; i < *samples; i++ )
	{
		for ( j = 0; j < *channels; j++ )
		{
			sample = *p * gain;
			*p = ROUND( sample );
		
			if ( gain > 1.0 )
			{
				/* use limiter function instead of clipping */
				if ( normalise )
					*p = ROUND( samplemax * limiter( sample / (double) samplemax, limiter_level ) );
				
				/* perform clipping */
				else if ( sample > samplemax )
					*p = samplemax;
				else if ( sample < samplemin )
					*p = samplemin;
			}
			p++;
		}
		gain += gain_step;
	}
	
	return 0;
}
Пример #16
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 );
    mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
    mlt_position position = mlt_filter_get_position( filter, frame );
    mlt_position length = mlt_filter_get_length2( filter, frame );

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

    // Only process if we have no error and a valid colour space
    if ( error == 0 )
    {
        // Get the charcoal scatter value
        int x_scatter = mlt_properties_anim_get_double( properties, "x_scatter", position, length );
        int y_scatter = mlt_properties_anim_get_double( properties, "y_scatter", position, length );
        float scale = mlt_properties_anim_get_double( properties, "scale" ,position, length);
        float mix = mlt_properties_anim_get_double( properties, "mix", position, length);
        int invert = mlt_properties_anim_get_int( properties, "invert", position, length);

        // We'll process pixel by pixel
        int x = 0;
        int y = 0;

        // We need to create a new frame as this effect modifies the input
        uint8_t *temp = mlt_pool_alloc( *width * *height * 2 );
        uint8_t *p = temp;
        uint8_t *q = *image;

        // Calculations are carried out on a 3x3 matrix
        int matrix[ 3 ][ 3 ];

        // Used to carry out the matrix calculations
        int sum1;
        int sum2;
        float sum;
        int val;

        // Loop for each row
        for ( y = 0; y < *height; y ++ )
        {
            // Loop for each pixel
            for ( x = 0; x < *width; x ++ )
            {
                // Populate the matrix
                matrix[ 0 ][ 0 ] = get_Y( *image, *width, *height, x - x_scatter, y - y_scatter );
                matrix[ 0 ][ 1 ] = get_Y( *image, *width, *height, x            , y - y_scatter );
                matrix[ 0 ][ 2 ] = get_Y( *image, *width, *height, x + x_scatter, y - y_scatter );
                matrix[ 1 ][ 0 ] = get_Y( *image, *width, *height, x - x_scatter, y             );
                matrix[ 1 ][ 2 ] = get_Y( *image, *width, *height, x + x_scatter, y             );
                matrix[ 2 ][ 0 ] = get_Y( *image, *width, *height, x - x_scatter, y + y_scatter );
                matrix[ 2 ][ 1 ] = get_Y( *image, *width, *height, x            , y + y_scatter );
                matrix[ 2 ][ 2 ] = get_Y( *image, *width, *height, x + x_scatter, y + y_scatter );

                // Do calculations
                sum1 = (matrix[2][0] - matrix[0][0]) + ( (matrix[2][1] - matrix[0][1]) << 1 ) + (matrix[2][2] - matrix[2][0]);
                sum2 = (matrix[0][2] - matrix[0][0]) + ( (matrix[1][2] - matrix[1][0]) << 1 ) + (matrix[2][2] - matrix[2][0]);
                sum = scale * sqrti( sum1 * sum1 + sum2 * sum2 );

                // Assign value
                *p ++ = !invert ? ( sum >= 16 && sum <= 235 ? 251 - sum : sum < 16 ? 235 : 16 ) :
                        ( sum >= 16 && sum <= 235 ? sum : sum < 16 ? 16 : 235 );
                q ++;
                val = 128 + mix * ( *q ++ - 128 );
                val = val < 16 ? 16 : val > 240 ? 240 : val;
                *p ++ = val;
            }
        }

        // Return the created image
        *image = temp;

        // Store new and destroy old
        mlt_frame_set_image( frame, *image, *width * *height * 2, mlt_pool_release );
    }

    return error;
}
Пример #17
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_yuv422;
	int error = mlt_frame_get_image( frame, image, format, width, height, 1 );

	if ( error == 0 && *image )
	{
		float smooth, radius, cx, cy, opac;
		mlt_properties filter_props = MLT_FILTER_PROPERTIES( filter ) ;
		mlt_position pos = mlt_filter_get_position( filter, frame );
		mlt_position len = mlt_filter_get_length2( filter, frame );

		smooth = mlt_properties_anim_get_double( filter_props, "smooth", pos, len ) * 100.0;
		radius = mlt_properties_anim_get_double( filter_props, "radius", pos, len ) * *width;
		cx = mlt_properties_anim_get_double( filter_props, "x", pos, len ) * *width;
		cy = mlt_properties_anim_get_double( filter_props, "y", pos, len ) * *height;
		opac = mlt_properties_anim_get_double( filter_props, "opacity", pos, len );
		int mode = mlt_properties_get_int( filter_props , "mode" );

		int video_width = *width;
		int video_height = *height;
		
		int x, y;
		int w2 = cx, h2 = cy;
		double delta = 1.0;
		double max_opac = opac;
		for ( y=0; y < video_height; y++ )
		{
			int h2_pow2 = pow( y - h2, 2.0 );
			for ( x = 0; x < video_width; x++ )
			{
				uint8_t *pix = ( *image + y * video_width * 2 + x * 2 );
				int dx = sqrt( h2_pow2 + pow( x - w2, 2.0 ));
				
				if (radius-smooth > dx) //center, make not darker
				{
					continue;
				}
				else if ( radius + smooth <= dx ) //max dark after smooth area
				{
					delta = 0.0;
				}
				else
				{
					// linear pos from of opacity (from 0 to 1)
					delta = (double) ( radius + smooth - dx ) / ( 2.0 * smooth );
					if ( mode == 1 )
					{
						//make cos for smoother non linear fade
						delta = (double) pow( cos((( 1.0 - delta ) * 3.14159 / 2.0 )), 3.0 );
					}
				}
				delta = MAX( max_opac, delta );
				*pix = (double) (*pix) * delta;
				*(pix+1) = ((double)(*(pix+1) - 127.0 ) * delta ) + 127.0;
			}
		}
	}

	return error;
}