示例#1
0
static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{
	context cx = mlt_frame_pop_service( frame );
	mlt_frame nested_frame = mlt_frame_pop_service( frame );

	*width = cx->profile->width;
	*height = cx->profile->height;

	int result = mlt_frame_get_image( nested_frame, image, format, width, height, writable );

	// Allocate the image
	int size = mlt_image_format_size( *format, *width, *height, NULL );
	uint8_t *new_image = mlt_pool_alloc( size );

	// Update the frame
	mlt_properties properties = mlt_frame_properties( frame );
	mlt_frame_set_image( frame, new_image, size, mlt_pool_release );
	memcpy( new_image, *image, size );
	mlt_properties_set( properties, "progressive", mlt_properties_get( MLT_FRAME_PROPERTIES(nested_frame), "progressive" ) );
	*image = new_image;
	
	// Copy the alpha channel
	uint8_t *alpha = mlt_properties_get_data( MLT_FRAME_PROPERTIES( nested_frame ), "alpha", &size );
	if ( alpha && size > 0 )
	{
		new_image = mlt_pool_alloc( size );
		memcpy( new_image, alpha, size );
		mlt_frame_set_alpha( frame, new_image, size, mlt_pool_release );
	}

	return result;
}
示例#2
0
static int get_image_b( mlt_frame b_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{
	mlt_transition self = mlt_frame_pop_service( b_frame );
	mlt_frame a_frame = mlt_frame_pop_frame( b_frame );
	mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame );
	mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame );

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

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

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

	return mlt_frame_get_image( b_frame, image, format, width, height, writable );
}
示例#3
0
static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ){
	
	mlt_frame b_frame = mlt_frame_pop_frame( a_frame );
	mlt_transition transition = mlt_frame_pop_service( a_frame );
	mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition );
	mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame );
	mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame );

	int invert = mlt_properties_get_int( properties, "invert" );

	uint8_t *images[]={NULL,NULL,NULL};

	*format = mlt_image_rgb24a;
	mlt_frame_get_image( a_frame, &images[0], format, width, height, 0 );
	mlt_frame_get_image( b_frame, &images[1], format, width, height, 0 );
	
	double position = mlt_transition_get_position( transition, a_frame );
	mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( transition ) );
	double time = position / mlt_profile_fps( profile );
	process_frei0r_item( MLT_TRANSITION_SERVICE(transition), position, time, properties, !invert ? a_frame : b_frame, images, width, height );
	
	*width = mlt_properties_get_int( !invert ? a_props : b_props, "width" );
        *height = mlt_properties_get_int( !invert ? a_props : b_props, "height" );
	*image = mlt_properties_get_data( !invert ? a_props : b_props , "image", NULL );
	return 0;
}
示例#4
0
static int attach_boundry_to_frame( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{
	// Get the filter object
	mlt_filter filter = mlt_frame_pop_service( frame );

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

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

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

	// Get the geometry object
	mlt_geometry geometry = mlt_properties_get_data(filter_properties, "filter_geometry", NULL);
	if (geometry == NULL) {
		mlt_geometry geom = mlt_geometry_init();
		char *arg = mlt_properties_get(filter_properties, "geometry");

		// Initialize with the supplied geometry
		struct mlt_geometry_item_s item;
		mlt_geometry_parse_item( geom, &item, arg  );

		item.frame = 0;
		item.key = 1;
		item.mix = 100;

		mlt_geometry_insert( geom, &item );
		mlt_geometry_interpolate( geom );
		mlt_properties_set_data( filter_properties, "filter_geometry", geom, 0, (mlt_destructor)mlt_geometry_close, (mlt_serialiser)mlt_geometry_serialise );
		geometry = mlt_properties_get_data(filter_properties, "filter_geometry", NULL);
	}

	mlt_service_unlock( MLT_FILTER_SERVICE( filter ) );

	// Get the current geometry item
	mlt_geometry_item geometry_item = mlt_pool_alloc( sizeof( struct mlt_geometry_item_s ) );
	mlt_geometry_fetch(geometry, geometry_item, position);

	// Cleanse the geometry item
	geometry_item->w = geometry_item->x < 0 ? geometry_item->w + geometry_item->x : geometry_item->w;
	geometry_item->h = geometry_item->y < 0 ? geometry_item->h + geometry_item->y : geometry_item->h;
	geometry_item->x = geometry_item->x < 0 ? 0 : geometry_item->x;
	geometry_item->y = geometry_item->y < 0 ? 0 : geometry_item->y;
	geometry_item->w = geometry_item->w < 0 ? 0 : geometry_item->w;
	geometry_item->h = geometry_item->h < 0 ? 0 : geometry_item->h;

	mlt_properties_set_data( frame_properties, "bounds", geometry_item, sizeof( struct mlt_geometry_item_s ), mlt_pool_release, NULL );

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

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

	return error;
}
示例#5
0
文件: mlt_tractor.c 项目: rt1729/mlt
static int producer_get_image( mlt_frame self, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
{
	uint8_t *data = NULL;
	int size = 0;
	mlt_properties properties = MLT_FRAME_PROPERTIES( self );
	mlt_frame frame = mlt_frame_pop_service( self );
	mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame );
	mlt_properties_set( frame_properties, "rescale.interp", mlt_properties_get( properties, "rescale.interp" ) );
	mlt_properties_set_int( frame_properties, "resize_alpha", mlt_properties_get_int( properties, "resize_alpha" ) );
	mlt_properties_set_int( frame_properties, "distort", mlt_properties_get_int( properties, "distort" ) );
	mlt_properties_set_int( frame_properties, "consumer_deinterlace", mlt_properties_get_int( properties, "consumer_deinterlace" ) );
	mlt_properties_set( frame_properties, "deinterlace_method", mlt_properties_get( properties, "deinterlace_method" ) );
	mlt_properties_set_int( frame_properties, "consumer_tff", mlt_properties_get_int( properties, "consumer_tff" ) );
	mlt_frame_get_image( frame, buffer, format, width, height, writable );
	mlt_frame_set_image( self, *buffer, 0, NULL );
	mlt_properties_set_int( properties, "width", *width );
	mlt_properties_set_int( properties, "height", *height );
	mlt_properties_set_int( properties, "format", *format );
	mlt_properties_set_double( properties, "aspect_ratio", mlt_frame_get_aspect_ratio( frame ) );
	mlt_properties_set_int( properties, "progressive", mlt_properties_get_int( frame_properties, "progressive" ) );
	mlt_properties_set_int( properties, "distort", mlt_properties_get_int( frame_properties, "distort" ) );
	mlt_properties_set_int( properties, "colorspace", mlt_properties_get_int( frame_properties, "colorspace" ) );
	mlt_properties_set_int( properties, "force_full_luma", mlt_properties_get_int( frame_properties, "force_full_luma" ) );
	mlt_properties_set_int( properties, "top_field_first", mlt_properties_get_int( frame_properties, "top_field_first" ) );
	mlt_properties_set_data( properties, "movit.convert.fence",
		mlt_properties_get_data( frame_properties, "movit.convert.fence", NULL ),
		0, NULL, NULL );
	data = mlt_frame_get_alpha_mask( frame );
	mlt_properties_get_data( frame_properties, "alpha", &size );
	mlt_frame_set_alpha( self, data, size, NULL );
	self->convert_image = frame->convert_image;
	self->convert_audio = frame->convert_audio;
	return 0;
}
示例#6
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 );
	int error = 0;


	// Regenerate the LUT if necessary
	mlt_service_lock( MLT_FILTER_SERVICE( filter ) );
	refresh_lut( filter, frame );
	mlt_service_unlock( MLT_FILTER_SERVICE( filter ) );

	// Make sure the format is acceptable
	if( *format != mlt_image_rgb24 && *format != mlt_image_rgb24a )
	{
		*format = mlt_image_rgb24;
	}

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

	// Apply the LUT
	if( !error )
	{
		apply_lut( filter, *image, *format, *width, *height );
	}

	return error;
}
示例#7
0
/** Get the image.
*/
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 );
	private_data* pdata = (private_data*)filter->child;
	mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame );

	if( mlt_properties_get_data( frame_properties, pdata->fft_prop_name, NULL ) )
	{
		// Get the current image
		*format = mlt_image_rgb24a;
		error = mlt_frame_get_image( frame, image, format, width, height, 1 );

		// Draw the spectrum
		if( !error ) {
			QImage qimg( *width, *height, QImage::Format_ARGB32 );
			copy_mlt_to_qimage_rgba( *image, &qimg );
			draw_spectrum( filter, frame, &qimg );
			copy_qimage_to_mlt_rgba( &qimg, *image );
		}
	} else {
		if ( pdata->preprocess_warned++ == 2 )
		{
			// This filter depends on the consumer processing the audio before
			// the video.
			mlt_log_warning( MLT_FILTER_SERVICE(filter), "Audio not preprocessed.\n" );
		}
		mlt_frame_get_image( frame, image, format, width, height, writable );
	}

	return error;
}
示例#8
0
static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *image_format, int *width, int *height, int writable )
{
	int error = 0;
	mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame );
	mlt_filter filter = (mlt_filter)mlt_frame_pop_service( frame );
	int samples = 0;
	int channels = 0;
	int frequency = 0;
	mlt_audio_format audio_format = mlt_audio_s16;
	int16_t* audio = (int16_t*)mlt_properties_get_data( frame_properties, "audio", NULL );

	if ( !audio && !preprocess_warned ) {
		// This filter depends on the consumer processing the audio before the
		// video. If the audio is not preprocessed, this filter will process it.
		// If this filter processes the audio, it could cause confusion for the
		// consumer if it needs different audio properties.
		mlt_log_warning( MLT_FILTER_SERVICE(filter), "Audio not preprocessed. Potential audio distortion.\n" );
		preprocess_warned = true;
	}

	*image_format = mlt_image_rgb24a;

	// Get the current image
	error = mlt_frame_get_image( frame, image, image_format, width, height, writable );

	// Get the audio
	if( !error ) {
		frequency = mlt_properties_get_int( frame_properties, "audio_frequency" );
		if (!frequency) {
			frequency = 48000;
		}
		channels = mlt_properties_get_int( frame_properties, "audio_channels" );
		if (!channels) {
			channels = 2;
		}
		samples = mlt_properties_get_int( frame_properties, "audio_samples" );
		if (!samples) {
			mlt_producer producer = mlt_frame_get_original_producer( frame );
			double fps = mlt_producer_get_fps( mlt_producer_cut_parent( producer ) );
			samples = mlt_sample_calculator( fps, frequency, mlt_frame_get_position( frame ) );
		}

		error = mlt_frame_get_audio( frame, (void**)&audio, &audio_format, &frequency, &channels, &samples );
	}

	// Draw the waveforms
	if( !error ) {
		QImage qimg( *width, *height, QImage::Format_ARGB32 );
		convert_mlt_to_qimage_rgba( *image, &qimg, *width, *height );
		draw_waveforms( filter, frame, &qimg, audio, channels, samples );
		convert_qimage_to_mlt_rgba( &qimg, *image, *width, *height );
	}

	return error;
}
示例#9
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;
			}
		}
示例#10
0
static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{
	context cx = mlt_frame_pop_service( frame );
	mlt_frame nested_frame = mlt_frame_pop_service( frame );

	*width = cx->profile->width;
	*height = cx->profile->height;

	int result = mlt_frame_get_image( nested_frame, image, format, width, height, writable );

	// Allocate the image
	int size = *width * *height * ( *format == mlt_image_yuv422 ? 2 : *format == mlt_image_rgb24 ? 3 :
		( *format == mlt_image_rgb24a || *format == mlt_image_opengl ) ? 4 : ( 3 / 2 ) );
	uint8_t *new_image = mlt_pool_alloc( size );

	// Update the frame
	mlt_properties properties = mlt_frame_properties( frame );
	mlt_properties_set_data( properties, "image", new_image, size, mlt_pool_release, NULL );
	memcpy( new_image, *image, size );
	mlt_properties_set( properties, "progressive", mlt_properties_get( MLT_FRAME_PROPERTIES(nested_frame), "progressive" ) );
	*image = new_image;

	return result;
}
示例#11
0
static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ){
	
	if (*format!=mlt_image_yuv422 ){
		return -1;
	}
	
	mlt_frame b_frame = mlt_frame_pop_frame( a_frame );
	mlt_transition transition = mlt_frame_pop_service( a_frame );
	mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition );
	mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame );
	mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame );

	int invert = mlt_properties_get_int( properties, "invert" );

	if ( mlt_properties_get( a_props, "rescale.interp" ) == NULL || !strcmp( mlt_properties_get( a_props, "rescale.interp" ), "none" ) )
		mlt_properties_set( a_props, "rescale.interp", "nearest" );

	// set consumer_aspect_ratio for a and b frame
	if ( mlt_properties_get_double( a_props, "aspect_ratio" ) == 0.0 )
		mlt_properties_set_double( a_props, "aspect_ratio", mlt_properties_get_double( a_props, "consumer_aspect_ratio" ) );
	if ( mlt_properties_get_double( b_props, "aspect_ratio" ) == 0.0 )
		mlt_properties_set_double( b_props, "aspect_ratio", mlt_properties_get_double( a_props, "consumer_aspect_ratio" ) );
	mlt_properties_set_double( b_props, "consumer_aspect_ratio", mlt_properties_get_double( a_props, "consumer_aspect_ratio" ) );

	if ( mlt_properties_get( b_props, "rescale.interp" ) == NULL || !strcmp( mlt_properties_get( b_props, "rescale.interp" ), "none" ) )
                mlt_properties_set( b_props, "rescale.interp", "nearest" );
	
	uint8_t *images[]={NULL,NULL,NULL};

	mlt_frame_get_image( a_frame, &images[0], format, width, height, 1 );
	mlt_frame_get_image( b_frame, &images[1], format, width, height, 1 );
	
	mlt_position in = mlt_transition_get_in( transition );
	mlt_position out = mlt_transition_get_out( transition );

	// Get the position of the frame
	char *name = mlt_properties_get( MLT_TRANSITION_PROPERTIES( transition ), "_unique_id" );
	mlt_position position = mlt_properties_get_position( MLT_FRAME_PROPERTIES( a_frame ), name );

	float pos=( float )( position - in ) / ( float )( out - in + 1 );
	
	process_frei0r_item( transition_type , pos , properties, !invert ? a_frame : b_frame , images , format, width,height, writable );
	
	*width = mlt_properties_get_int( !invert ? a_props : b_props, "width" );
        *height = mlt_properties_get_int( !invert ? a_props : b_props, "height" );
	*image = mlt_properties_get_data( !invert ? a_props : b_props , "image", NULL );
	return 0;
}
示例#12
0
/** Get the image.
*/
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_frame_pop_service( frame );
	mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
	mlt_producer producer = mlt_properties_get_data( properties, "_producer", NULL );
	mlt_transition transition = mlt_properties_get_data( properties, "_transition", NULL );
	mlt_frame text_frame = NULL;
	mlt_position position = 0;

	// Configure this filter
	mlt_service_lock( MLT_FILTER_SERVICE( filter ) );
	setup_producer( filter, producer, frame );
	setup_transition( filter, transition );
	mlt_service_unlock( MLT_FILTER_SERVICE( filter ) );

	// Make sure the producer is in the correct position
	position = mlt_filter_get_position( filter, frame );
	mlt_producer_seek( producer, position );

	// Get the b frame and process with transition if successful
	if ( mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &text_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( text_frame );

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

		// Apply all filters that are attached to this filter to the b frame
		mlt_service_apply_filters( MLT_FILTER_SERVICE( filter ), text_frame, 0 );

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

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

		// Close the b frame
		mlt_frame_close( text_frame );
	}

	return error;
}
示例#13
0
static int get_image_a( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{
	mlt_transition self = mlt_frame_pop_service( a_frame );
	mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame );

	// All transitions get scaling
	const char *rescale = mlt_properties_get( a_props, "rescale.interp" );
	if ( !rescale || !strcmp( rescale, "none" ) )
		mlt_properties_set( a_props, "rescale.interp", "nearest" );

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

	return mlt_frame_get_image( a_frame, image, format, width, height, writable );
}
示例#14
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;
}
示例#15
0
static int 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 );
	uint8_t* vs_image = NULL;
	VSPixelFormat vs_format = PF_NONE;

	// VS only works on progressive frames
	mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "consumer_deinterlace", 1 );

	*format = validate_format( *format );

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

	// Convert the received image to a format vid.stab can handle
	if ( !error )
	{
		vs_format = mltimage_to_vsimage( *format, *width, *height, *image, &vs_image );
	}

	if( vs_image )
	{
		mlt_service_lock( MLT_FILTER_SERVICE(filter) );

		char* results = mlt_properties_get( properties, "results" );
		if( results && strcmp( results, "" ) )
		{
			apply_results( filter, frame, vs_image, vs_format, *width, *height );
			vsimage_to_mltimage( vs_image, *image, *format, *width, *height );
		}
		else
		{
			analyze_image( filter, frame, vs_image, vs_format, *width, *height );
			if( mlt_properties_get_int( properties, "show" ) == 1 )
			{
				vsimage_to_mltimage( vs_image, *image, *format, *width, *height );
			}
		}

		mlt_service_unlock( MLT_FILTER_SERVICE(filter) );

		free_vsimage( vs_image, vs_format );
	}

	return error;
}
示例#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_rgb24a;
	mlt_log_debug( MLT_FILTER_SERVICE( filter ), "frei0r %dx%d\n", *width, *height );
	int error = mlt_frame_get_image( frame, image, format, width, height, 0 );

	if ( error == 0 && *image )
	{
		double position = mlt_filter_get_position( filter, frame );
		mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) );
		double time = position / mlt_profile_fps( profile );
		int length = mlt_filter_get_length2( filter, frame );
		process_frei0r_item( MLT_FILTER_SERVICE(filter), position, time, length, frame, image, width, height );
	}

	return error;
}
示例#17
0
static int producer_get_image( mlt_frame frame, uint8_t** image, mlt_image_format* format, int* width, int* height, int writable )
{
	mlt_producer producer = mlt_frame_pop_service( frame );
	mlt_frame bg_frame = NULL;
	mlt_frame text_frame = NULL;
	int error = 1;
	int size = 0;
	char* background = mlt_properties_get( MLT_PRODUCER_PROPERTIES( producer ), "background" );
	time_info info;

	mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) );

	get_time_info( producer, frame, &info );

	bg_frame = get_background_frame( producer );
	if( !strcmp( background, "clock" ) )
	{
		add_clock_to_frame( producer, bg_frame, &info );
	}
	text_frame = get_text_frame( producer, &info );
	add_text_to_bg( producer, bg_frame, text_frame );

	if( bg_frame )
	{
		// Get the image from the background frame.
		error = mlt_frame_get_image( bg_frame, image, format, width, height, writable );
		size = mlt_image_format_size( *format, *width, *height, NULL );
		// Detach the image from the bg_frame so it is not released.
		mlt_frame_set_image( bg_frame, *image, size, NULL );
		// Attach the image to the input frame.
		mlt_frame_set_image( frame, *image, size, mlt_pool_release );
		mlt_frame_close( bg_frame );
	}

	if( text_frame )
	{
		mlt_frame_close( text_frame );
	}

	mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) );

	return error;
}
示例#18
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;
}
示例#19
0
static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{
	// Pop the service
	mlt_filter filter = mlt_frame_pop_service( frame );

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

	mlt_service_lock( MLT_FILTER_SERVICE( filter ) );

	// Track specific
	process_queue( mlt_properties_get_data( frame_properties, "data_queue", NULL ), frame, filter );

	// Global
	process_queue( mlt_properties_get_data( frame_properties, "global_queue", NULL ), frame, filter );

	mlt_service_unlock( MLT_FILTER_SERVICE( filter ) );

	// Need to get the image
	return mlt_frame_get_image( frame, image, format, width, height, 1 );
}
示例#20
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;
}
示例#21
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 );
}
示例#22
0
static int get_image(mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable)
{
	mlt_transition transition = mlt_frame_pop_service(frame);
	*format = mlt_frame_pop_service_int(frame);
	int error = mlt_frame_get_image(frame, image, format, width, height, writable);
	if (!error) {
		mlt_properties properties = MLT_FRAME_PROPERTIES(frame);
		mlt_frame clone = mlt_properties_get_data(properties, "mask frame", NULL);
		if (clone) {
			mlt_frame_push_get_image(frame, dummy_get_image);
			mlt_service_lock(MLT_TRANSITION_SERVICE(transition));
			mlt_transition_process(transition, clone, frame);
			mlt_service_unlock(MLT_TRANSITION_SERVICE(transition));
			error = mlt_frame_get_image(clone, image, format, width, height, writable);
			if (!error) {
				int size = mlt_image_format_size(*format, *width, *height, NULL);
				mlt_frame_set_image(frame, *image, size, NULL);
			}
		}
	}
	return error;
}
示例#23
0
文件: filter_gamma.c 项目: aib/mlt
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;
}
示例#24
0
int get_image_and_detect(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);

	*format = mlt_image_yuv420p;

	writable = writable || mlt_properties_get_int(properties, "show") ? 1 : 0;

	int error = mlt_frame_get_image(frame, image, format, width, height, writable);
	if (!error)
	{
		// Service locks are for concurrency control
		mlt_service_lock(MLT_FILTER_SERVICE(filter));

		StabData *data = static_cast<StabData*>(mlt_properties_get_data(properties, "_stab_data", NULL));
		if (!data)
		{
			data = init_detect(properties, format, width, height);
			mlt_properties_set_data(properties, "_stab_data", data, 0, (mlt_destructor) destroy_detect, NULL);
		}

		VSMotionDetect* md = &data->md;
		LocalMotions localmotions;
		VSFrame vsFrame;
		vsFrameFillFromBuffer(&vsFrame, *image, &md->fi);

		// detect and save motions
		vsMotionDetection(md, &localmotions, &vsFrame);
		mlt_position pos = mlt_filter_get_position( filter, frame );
		serialize_localmotions(data, localmotions, pos);

		mlt_service_unlock(MLT_FILTER_SERVICE(filter));
	}

	return error;
}
示例#25
0
static int transitionGetImage(mlt_frame aFrame, uint8_t **image, mlt_image_format *format, int *width, int *height, int /*writable*/) {
    int error = 0;

    mlt_frame bFrame = mlt_frame_pop_frame(aFrame);
    mlt_transition transition = (mlt_transition)mlt_frame_pop_service(aFrame);

    mlt_position position = mlt_transition_get_position(transition, aFrame);
    mlt_position length = mlt_transition_get_length(transition);

    // Get the aFrame image, we will write our output to it
    *format = mlt_image_rgb24;
    if ((error = mlt_frame_get_image(aFrame, image, format, width, height, 1)) != 0)
        return error;
    // Get the bFrame image, we won't write to it
    uint8_t *bImage = NULL;
    int bWidth = 0, bHeight = 0;
    if ((error = mlt_frame_get_image(bFrame, &bImage, format, &bWidth, &bHeight, 0)) != 0)
        return error;

    { // Scope the lock
        MLTWebVfx::ServiceLocker locker(MLT_TRANSITION_SERVICE(transition));
        if (!locker.initialize(*width, *height))
            return 1;

        MLTWebVfx::ServiceManager* manager = locker.getManager();
        WebVfx::Image renderedImage(*image, *width, *height,
                                    *width * *height * WebVfx::Image::BytesPerPixel);
        manager->setImageForName(manager->getSourceImageName(), &renderedImage);
        WebVfx::Image targetImage(bImage, bWidth, bHeight,
                                  bWidth * bHeight * WebVfx::Image::BytesPerPixel);
        manager->setImageForName(manager->getTargetImageName(), &targetImage);
        manager->render(&renderedImage, position, length);
    }

    return error;
}
示例#26
0
						// FIXME: may exceed boundies
						*(r-1) =  ( 1.0 - scale ) * ( (double)(*(f-1) + (double)f[3]) / 2.0 ) + scale * (double) s[1];
				}
//			 }
		 }
		}
	 }
	}
}

// Image stack(able) method
static int slowmotion_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{

	// Get the filter object and properties
	mlt_producer producer = mlt_frame_pop_service( this );
	mlt_frame second_frame = mlt_frame_pop_service( this );
	mlt_frame first_frame = mlt_frame_pop_service( this );

	mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer );

	// Frame properties objects
	mlt_properties frame_properties = MLT_FRAME_PROPERTIES( this );
	mlt_properties first_frame_properties = MLT_FRAME_PROPERTIES( first_frame );
	mlt_properties second_frame_properties = MLT_FRAME_PROPERTIES( second_frame );

	// image stride
	int size, xstride, ystride;
	switch( *format ){
		case mlt_image_yuv422:
			size = *width * *height * 2;
示例#27
0
文件: filter_frei0r.c 项目: rayl/MLT
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <framework/mlt.h>

#include "frei0r_helper.h"
#include <string.h>
static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{

	mlt_filter filter = mlt_frame_pop_service( this );
	int error = mlt_frame_get_image( this, image, format, width, height, 1 );
	
	if ( error == 0 && *image && *format == mlt_image_yuv422 )
	{
		mlt_position in = mlt_filter_get_in( filter );
		mlt_position out = mlt_filter_get_out( filter );
		mlt_position time = mlt_frame_get_position( this );
		double position = ( double )( time - in ) / ( double )( out - in + 1 );
		
		process_frei0r_item( filter_type , position, MLT_FILTER_PROPERTIES ( filter ), this , image, format , width , height , writable );
		
	}

	return error;
}
示例#28
0
static int get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{
	mlt_frame b_frame = mlt_frame_pop_frame( a_frame );
	mlt_properties properties = MLT_FRAME_PROPERTIES( a_frame );
	mlt_transition transition = MLT_TRANSITION( mlt_frame_pop_service( a_frame ) );
	uint8_t *b_image;
	int window_size = mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( transition ), "window_size" );
	double psnr[3], ssim[3];

	*format = mlt_image_yuv422;
	mlt_frame_get_image( b_frame, &b_image, format, width, height, writable );
	mlt_frame_get_image( a_frame, image, format, width, height, writable );

	psnr[0] = calc_psnr( *image, b_image, *width * *height, 2 );
	psnr[1] = calc_psnr( *image + 1, b_image + 1, *width * *height / 2, 4 );
	psnr[2] = calc_psnr( *image + 3, b_image + 3, *width * *height / 2, 4 );
	ssim[0] = calc_ssim( *image, b_image, *width, *height, window_size, 2 );
	ssim[1] = calc_ssim( *image + 1, b_image + 1, *width / 2, *height, window_size, 4 );
	ssim[2] = calc_ssim( *image + 3, b_image + 3, *width / 2, *height, window_size, 4 );
	mlt_properties_set_double( properties, "meta.vqm.psnr.y", psnr[0] );
	mlt_properties_set_double( properties, "meta.vqm.psnr.cb", psnr[1] );
	mlt_properties_set_double( properties, "meta.vqm.psnr.cr", psnr[2] );
	mlt_properties_set_double( properties, "meta.vqm.ssim.y", ssim[0] );
	mlt_properties_set_double( properties, "meta.vqm.ssim.cb", ssim[1] );
	mlt_properties_set_double( properties, "meta.vqm.ssim.cr", ssim[2] );
	printf( "%05d %05.2f %05.2f %05.2f %5.3f %5.3f %5.3f\n",
			mlt_frame_get_position( a_frame ), psnr[0], psnr[1], psnr[2],
			ssim[0], ssim[1], ssim[2] );

	// copy the B frame to the bottom of the A frame for comparison
	window_size = mlt_image_format_size( *format, *width, *height, NULL ) / 2;
	memcpy( *image + window_size, b_image + window_size, window_size );

	if ( !mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( transition ), "render" ) )
		return 0;

	// get RGBA image for Qt drawing
	*format = mlt_image_rgb24a;
	mlt_frame_get_image( a_frame, image, format, width, height, 1 );

	// convert mlt image to qimage
	QImage img( *width, *height, QImage::Format_ARGB32 );
	int y = *height + 1;
	uint8_t *src = *image;
	while ( --y )
	{
		QRgb *dst = (QRgb*) img.scanLine( *height - y );
		int x = *width + 1;
		while ( --x )
		{
			*dst++ = qRgba( src[0], src[1], src[2], 255 );
			src += 4;
		}
	}

	// setup Qt drawing
	QPainter painter;
	painter.begin( &img );
	painter.setRenderHints( QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::HighQualityAntialiasing );

	// draw some stuff with Qt
	QPalette palette;
	QFont font;
	QString s;
	font.setBold( true );
	font.setPointSize( 30 * *height / 1080 );
	painter.setPen( QColor("black") );
	painter.drawLine( 0, *height/2 + 1, *width, *height/2 );
	painter.setPen( QColor("white") );
	painter.drawLine( 0, *height/2 - 1, *width, *height/2 );
	painter.setFont( font );
	s.sprintf( "Frame: %05d\nPSNR:   %05.2f (Y) %05.2f (Cb) %05.2f (Cr)\nSSIM:    %5.3f (Y) %5.3f (Cb) %5.3f (Cr)",
			  mlt_frame_get_position( a_frame ), psnr[0], psnr[1], psnr[2],
			  ssim[0], ssim[1], ssim[2] );
	painter.setPen( QColor("black") );
	painter.drawText( 52, *height * 8 / 10 + 2, *width, *height, 0, s );
	painter.setPen( QColor("white") );
	painter.drawText( 50, *height * 8 / 10, *width, *height, 0, s );

	// finish Qt drawing
	painter.end();
	window_size = mlt_image_format_size( *format, *width, *height, NULL );
	uint8_t *dst = (uint8_t *) mlt_pool_alloc( window_size );
	mlt_properties_set_data( MLT_FRAME_PROPERTIES(a_frame), "image", dst, window_size, mlt_pool_release, NULL );
	*image = dst;

	// convert qimage to mlt
	y = *height + 1;
	while ( --y )
	{
		QRgb *src = (QRgb*) img.scanLine( *height - y );
		int x = *width + 1;
		while ( --x )
		{
			*dst++ = qRed( *src );
			*dst++ = qGreen( *src );
			*dst++ = qBlue( *src );
			*dst++ = qAlpha( *src );
			src++;
		}
	}

	return 0;
}
示例#29
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;
}
示例#30
0
static int framebuffer_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{

	// Get the filter object and properties
	mlt_producer producer = mlt_frame_pop_service( frame );
	int index = ( int )mlt_frame_pop_service( frame );
	mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );

	mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) );

	// Frame properties objects
	mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame );
	mlt_frame first_frame = mlt_properties_get_data( properties, "first_frame", NULL );

	// Get producer parameters
	int strobe = mlt_properties_get_int( properties, "strobe" );
	int freeze = mlt_properties_get_int( properties, "freeze" );
	int freeze_after = mlt_properties_get_int( properties, "freeze_after" );
	int freeze_before = mlt_properties_get_int( properties, "freeze_before" );
	int in = mlt_properties_get_position( properties, "in" );

	// Determine the position
	mlt_position first_position = (first_frame != NULL) ? mlt_frame_get_position( first_frame ) : -1;
	mlt_position need_first = freeze;

	if ( !freeze || freeze_after || freeze_before )
	{
		double prod_speed = mlt_properties_get_double( properties, "_speed" );
		double actual_position = in + prod_speed * (double) mlt_producer_position( producer );

		if ( mlt_properties_get_int( properties, "reverse" ) )
			actual_position = mlt_producer_get_playtime( producer ) - actual_position;

		if ( strobe < 2 )
		{
			need_first = floor( actual_position );
		}
		else
		{
			// Strobe effect wanted, calculate frame position
			need_first = floor( actual_position );
			need_first -= need_first % strobe;
		}
		if ( freeze )
		{
			if ( freeze_after && need_first > freeze ) need_first = freeze;
			else if ( freeze_before && need_first < freeze ) need_first = freeze;
		}
	}
	
	// Determine output buffer size
	*width = mlt_properties_get_int( frame_properties, "width" );
	*height = mlt_properties_get_int( frame_properties, "height" );
	int size = mlt_image_format_size( *format, *width, *height, NULL );

	// Get output buffer
	int buffersize = 0;
        int alphasize = *width * *height;
	uint8_t *output = mlt_properties_get_data( properties, "output_buffer", &buffersize );
        uint8_t *output_alpha = mlt_properties_get_data( properties, "output_alpha", NULL );
	if( buffersize == 0 || buffersize != size )
	{
		// invalidate cached frame
		first_position = -1;
	}

	if ( need_first != first_position )
	{
		// invalidate cached frame
		first_position = -1;
		
		// Bust the cached frame
		mlt_properties_set_data( properties, "first_frame", NULL, 0, NULL, NULL );
		first_frame = NULL;
	}

	if ( output && first_position != -1 ) {
		// Using the cached frame
	  	uint8_t *image_copy = mlt_pool_alloc( size );
		memcpy( image_copy, output, size );
                uint8_t *alpha_copy = mlt_pool_alloc( alphasize );
                memcpy( alpha_copy, output_alpha, alphasize );

		// Set the output image
		*image = image_copy;
		mlt_frame_set_image( frame, image_copy, size, mlt_pool_release );
                mlt_frame_set_alpha( frame, alpha_copy, alphasize, mlt_pool_release );

		*width = mlt_properties_get_int( properties, "_output_width" );
		*height = mlt_properties_get_int( properties, "_output_height" );
		*format = mlt_properties_get_int( properties, "_output_format" );

		mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) );
		return 0;
	}

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

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

		// Get the frame
		mlt_service_get_frame( MLT_PRODUCER_SERVICE( real_producer ), &first_frame, index );

		// Cache the frame
		mlt_properties_set_data( properties, "first_frame", first_frame, 0, ( mlt_destructor )mlt_frame_close, NULL );
	}
	mlt_properties first_frame_properties = MLT_FRAME_PROPERTIES( first_frame );


	// Which frames are buffered?
	uint8_t *first_image = mlt_properties_get_data( first_frame_properties, "image", NULL );
        uint8_t *first_alpha = mlt_properties_get_data( first_frame_properties, "alpha", NULL );
	if ( !first_image )
	{
		mlt_properties_set( first_frame_properties, "rescale.interp", mlt_properties_get( frame_properties, "rescale.interp" ) );

		int error = mlt_frame_get_image( first_frame, &first_image, format, width, height, writable );

		if ( error != 0 ) {
			mlt_log_error( MLT_PRODUCER_SERVICE( producer ), "first_image == NULL get image died\n" );
			mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) );
			return error;
		}
		output = mlt_pool_alloc( size );
		memcpy( output, first_image, size );
		// Let someone else clean up
		mlt_properties_set_data( properties, "output_buffer", output, size, mlt_pool_release, NULL ); 
		mlt_properties_set_int( properties, "_output_width", *width );
		mlt_properties_set_int( properties, "_output_height", *height );
		mlt_properties_set_int( properties, "_output_format", *format );
	
	}

	if ( !first_alpha )
        {
                alphasize = *width * *height;
                first_alpha = mlt_frame_get_alpha_mask( first_frame );
                output_alpha = mlt_pool_alloc( alphasize );
                memcpy( output_alpha, first_alpha, alphasize );
                mlt_properties_set_data( properties, "output_alpha", output_alpha, alphasize, mlt_pool_release, NULL ); 
        }

	mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) );

	// Create a copy
	uint8_t *image_copy = mlt_pool_alloc( size );
	memcpy( image_copy, first_image, size );
        uint8_t *alpha_copy = mlt_pool_alloc( alphasize );
        memcpy( alpha_copy, first_alpha, alphasize );

	// Set the output image
	*image = image_copy;
	mlt_frame_set_image( frame, *image, size, mlt_pool_release );

	mlt_frame_set_alpha( frame, alpha_copy, alphasize, mlt_pool_release );

	return 0;
}