Beispiel #1
0
static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
{
	// Obtain properties of frame
	mlt_properties properties = MLT_FRAME_PROPERTIES( frame );

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

	mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) );

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

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

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

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

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

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

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

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

		mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) );

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

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

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

	// Create the alpha channel
	int alpha_size = *width * *height;
	uint8_t *alpha = mlt_pool_alloc( alpha_size );

	// Initialise the alpha
	if ( alpha )
		memset( alpha, color.a, alpha_size );

	// Clone our image
	*buffer = mlt_pool_alloc( size );
	memcpy( *buffer, image, size );

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


	return 0;
}
Beispiel #2
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 );

	// Structures for geometry
	struct mlt_geometry_item_s result;

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

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

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

	float geometry_w = result.w;
	float 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 );

	// 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.
	char *interps = mlt_properties_get( a_props, "rescale.interp" );
	if ( interps )
		interps = strdup( interps );
	mlt_properties_set( b_props, "rescale.interp", "none" );

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

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

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

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

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

		affine_init( affine.matrix );

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

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

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

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

	return 0;
}
Beispiel #3
0
static int filter_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
{
	mlt_properties properties = mlt_frame_pop_audio( frame );
	mlt_filter filter = mlt_frame_pop_audio( frame );
	mlt_properties filter_props = MLT_FILTER_PROPERTIES( filter );
	mlt_properties frame_props = MLT_FRAME_PROPERTIES( frame );

	// We can only mix s16
	*format = mlt_audio_s16;
	mlt_frame_get_audio( frame, (void**) buffer, format, frequency, channels, samples );

	// Apply silence
	int silent = mlt_properties_get_int( frame_props, "silent_audio" );
	mlt_properties_set_int( frame_props, "silent_audio", 0 );
	if ( silent )
		memset( *buffer, 0, *samples * *channels * sizeof( int16_t ) );

	int src_size = 0;
	int16_t *src = mlt_properties_get_data( filter_props, "scratch_buffer", &src_size );
	int16_t *dest = *buffer;
	double v; // sample accumulator
	int i, out, in;
	double factors[6][6]; // mixing weights [in][out]
	double mix_start = 0.5, mix_end = 0.5;
	if ( mlt_properties_get( properties, "previous_mix" ) != NULL )
		mix_start = mlt_properties_get_double( properties, "previous_mix" );
	if ( mlt_properties_get( properties, "mix" ) != NULL )
		mix_end = mlt_properties_get_double( properties, "mix" );
	double weight = mix_start;
	double weight_step = ( mix_end - mix_start ) / *samples;
	int active_channel = mlt_properties_get_int( properties, "channel" );
	int gang = mlt_properties_get_int( properties, "gang" ) ? 2 : 1;
	// Use an inline low-pass filter to help avoid clipping
	double Fc = 0.5;
	double B = exp(-2.0 * M_PI * Fc);
	double A = 1.0 - B;
	double vp[6];

	// Setup or resize a scratch buffer
	if ( !src || src_size < *samples * *channels * sizeof(int16_t) )
	{
		// We allocate 4 more samples than we need to deal with jitter in the sample count per frame.
		src_size = ( *samples + 4 ) * *channels * sizeof(int16_t);
		src = mlt_pool_alloc( src_size );
		if ( !src )
			return 0;
		mlt_properties_set_data( filter_props, "scratch_buffer", src, src_size, mlt_pool_release, NULL );
	}

	// We must use a pristine copy as the source
	memcpy( src, *buffer, *samples * *channels * sizeof(int16_t) );

	// Initialize the mix factors
	for ( i = 0; i < 6; i++ )
		for ( out = 0; out < 6; out++ )
			factors[i][out] = 0.0;

	for ( out = 0; out < *channels; out++ )
		vp[out] = (double) dest[out];

	for ( i = 0; i < *samples; i++ )
	{
		// Recompute the mix factors
		switch ( active_channel )
		{
			case -1: // Front L/R balance
			case -2: // Rear L/R balance
			{
				// Gang front/rear balance if requested
				int g, active = active_channel;
				for ( g = 0; g < gang; g++, active-- )
				{
					int left = active == -1 ? 0 : 2;
					int right = left + 1;
					if ( weight < 0.0 )
					{
						factors[left][left] = 1.0;
						factors[right][right] = weight + 1.0 < 0.0 ? 0.0 : weight + 1.0;
					}
					else
					{
						factors[left][left] = 1.0 - weight < 0.0 ? 0.0 : 1.0 - weight;
						factors[right][right] = 1.0;
					}
				}
				break;
			}
			case -3: // Left fade
			case -4: // right fade
			{
				// Gang left/right fade if requested
				int g, active = active_channel;
				for ( g = 0; g < gang; g++, active-- )
				{
					int front = active == -3 ? 0 : 1;
					int rear = front + 2;
					if ( weight < 0.0 )
					{
						factors[front][front] = 1.0;
						factors[rear][rear] = weight + 1.0 < 0.0 ? 0.0 : weight + 1.0;
					}
					else
					{
						factors[front][front] = 1.0 - weight < 0.0 ? 0.0 : 1.0 - weight;
						factors[rear][rear] = 1.0;
					}
				}
				break;
			}
			case 0: // left
			case 2:
			{
				int left = active_channel;
				int right = left + 1;
				factors[right][right] = 1.0;
				if ( weight < 0.0 ) // output left toward left
				{
					factors[left][left] = 0.5 - weight * 0.5;
					factors[left][right] = ( 1.0 + weight ) * 0.5;
				}
				else // output left toward right
				{
					factors[left][left] = ( 1.0 - weight ) * 0.5;
					factors[left][right] = 0.5 + weight * 0.5;
				}
				break;
			}
			case 1: // right
			case 3:
			{
				int right = active_channel;
				int left = right - 1;
				factors[left][left] = 1.0;
				if ( weight < 0.0 ) // output right toward left
				{
					factors[right][left] = 0.5 - weight * 0.5;
					factors[right][right] = ( 1.0 + weight ) * 0.5;
				}
				else // output right toward right
				{
					factors[right][left] = ( 1.0 - weight ) * 0.5;
					factors[right][right] = 0.5 + weight * 0.5;
				}
				break;
			}
		}

		// Do the mixing
		for ( out = 0; out < *channels && out < 6; out++ )
		{
			v = 0;
			for ( in = 0; in < *channels && in < 6; in++ )
				v += factors[in][out] * src[ i * *channels + in ];

			v = v < -32767 ? -32767 : v > 32768 ? 32768 : v;
			vp[out] = dest[ i * *channels + out ] = (int16_t) ( v * A + vp[ out ] * B );
		}
		weight += weight_step;
	}

	return 0;
}
Beispiel #4
0
static int jack_process (jack_nframes_t frames, void * data)
{
	mlt_filter filter = (mlt_filter) data;
 	mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
	int channels = mlt_properties_get_int( properties, "channels" );
	int frame_size = mlt_properties_get_int( properties, "_samples" ) * sizeof(float);
	int sync = mlt_properties_get_int( properties, "_sync" );
	int err = 0;
	int i;
	static int total_size = 0;
  
	jack_ringbuffer_t **output_buffers = mlt_properties_get_data( properties, "output_buffers", NULL );
	if ( output_buffers == NULL )
		return 0;
	jack_ringbuffer_t **input_buffers = mlt_properties_get_data( properties, "input_buffers", NULL );
	jack_port_t **jack_output_ports = mlt_properties_get_data( properties, "jack_output_ports", NULL );
	jack_port_t **jack_input_ports = mlt_properties_get_data( properties, "jack_input_ports", NULL );
	float **jack_output_buffers = mlt_properties_get_data( properties, "jack_output_buffers", NULL );
	float **jack_input_buffers = mlt_properties_get_data( properties, "jack_input_buffers", NULL );
	pthread_mutex_t *output_lock = mlt_properties_get_data( properties, "output_lock", NULL );
	pthread_cond_t *output_ready = mlt_properties_get_data( properties, "output_ready", NULL );
	
	for ( i = 0; i < channels; i++ )
	{
		size_t jack_size = ( frames * sizeof(float) );
		size_t ring_size;
		
		// Send audio through out port
		jack_output_buffers[i] = jack_port_get_buffer( jack_output_ports[i], frames );
		if ( ! jack_output_buffers[i] )
		{
			mlt_log_error( MLT_FILTER_SERVICE(filter), "no buffer for output port %d\n", i );
			err = 1;
			break;
		}
		ring_size = jack_ringbuffer_read_space( output_buffers[i] );
		jack_ringbuffer_read( output_buffers[i], ( char * )jack_output_buffers[i], ring_size < jack_size ? ring_size : jack_size );
		if ( ring_size < jack_size )
			memset( &jack_output_buffers[i][ring_size], 0, jack_size - ring_size );
		
		// Return audio through in port
		jack_input_buffers[i] = jack_port_get_buffer( jack_input_ports[i], frames );
		if ( ! jack_input_buffers[i] )
		{
			mlt_log_error( MLT_FILTER_SERVICE(filter), "no buffer for input port %d\n", i );
			err = 1;
			break;
		}
		
		// Do not start returning audio until we have sent first mlt frame
		if ( sync && i == 0 && frame_size > 0 )
			total_size += ring_size;
		mlt_log_debug( MLT_FILTER_SERVICE(filter), "sync %d frame_size %d ring_size %zu jack_size %zu\n", sync, frame_size, ring_size, jack_size );
		
		if ( ! sync || ( frame_size > 0  && total_size >= frame_size ) )
		{
			ring_size = jack_ringbuffer_write_space( input_buffers[i] );
			jack_ringbuffer_write( input_buffers[i], ( char * )jack_input_buffers[i], ring_size < jack_size ? ring_size : jack_size );
			
			if ( sync )
			{
				// Tell mlt that audio is available
				pthread_mutex_lock( output_lock);
				pthread_cond_signal( output_ready );
				pthread_mutex_unlock( output_lock);

				// Clear sync phase
				mlt_properties_set_int( properties, "_sync", 0 );
			}
		}
	}

	// Often jackd does not send the stopped event through the JackSyncCallback
	jack_client_t *jack_client = mlt_properties_get_data( properties, "jack_client", NULL );
	jack_position_t jack_pos;
	jack_transport_state_t state = jack_transport_query( jack_client, &jack_pos );
	int transport_state = mlt_properties_get_int( properties, "_transport_state" );
	if ( state != transport_state )
	{
		mlt_properties_set_int( properties, "_transport_state", state );
		if ( state == JackTransportStopped )
			jack_sync( state, &jack_pos, filter );
	}

	return err;
}
Beispiel #5
0
static int refresh_pixbuf( producer_pixbuf self, mlt_frame frame )
{
	// Obtain properties of frame and producer
	mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
	mlt_producer producer = &self->parent;
	mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer );

	// Check if user wants us to reload the image
	if ( mlt_properties_get_int( producer_props, "force_reload" ) )
	{
		self->pixbuf = NULL;
		self->image = NULL;
		mlt_properties_set_int( producer_props, "force_reload", 0 );
	}

	// Get the time to live for each frame
	double ttl = mlt_properties_get_int( producer_props, "ttl" );

	// Get the original position of this frame
	mlt_position position = mlt_frame_original_position( frame );
	position += mlt_producer_get_in( producer );

	// Image index
	int loop = mlt_properties_get_int( producer_props, "loop" );
	int current_idx;
	if (loop) {
		current_idx = ( int )floor( ( double )position / ttl ) % self->count;
	} else {
		current_idx = MIN(( double )position / ttl, self->count - 1);
	}

	// Key for the cache
	char image_key[ 10 ];
	sprintf( image_key, "%d", current_idx );

	int disable_exif = mlt_properties_get_int( producer_props, "disable_exif" );

	if ( current_idx != self->pixbuf_idx )
		self->pixbuf = NULL;
	if ( !self->pixbuf || mlt_properties_get_int( producer_props, "_disable_exif" ) != disable_exif )
	{
		GError *error = NULL;

		self->image = NULL;
		pthread_mutex_lock( &g_mutex );
		self->pixbuf = gdk_pixbuf_new_from_file( mlt_properties_get_value( self->filenames, current_idx ), &error );
		if ( self->pixbuf )
		{
			// Read the exif value for this file
			if ( !disable_exif )
				self->pixbuf = reorient_with_exif( self, current_idx, self->pixbuf );

			// Register this pixbuf for destruction and reuse
			mlt_cache_item_close( self->pixbuf_cache );
			mlt_service_cache_put( MLT_PRODUCER_SERVICE( producer ), "pixbuf.pixbuf", self->pixbuf, 0, ( mlt_destructor )g_object_unref );
			self->pixbuf_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "pixbuf.pixbuf" );
			self->pixbuf_idx = current_idx;

			// Store the width/height of the pixbuf temporarily
			self->width = gdk_pixbuf_get_width( self->pixbuf );
			self->height = gdk_pixbuf_get_height( self->pixbuf );

			mlt_events_block( producer_props, NULL );
			mlt_properties_set_int( producer_props, "meta.media.width", self->width );
			mlt_properties_set_int( producer_props, "meta.media.height", self->height );
			mlt_properties_set_int( producer_props, "_disable_exif", disable_exif );
			mlt_events_unblock( producer_props, NULL );

		}
		pthread_mutex_unlock( &g_mutex );
	}

	// Set width/height of frame
	mlt_properties_set_int( properties, "width", self->width );
	mlt_properties_set_int( properties, "height", self->height );

	return current_idx;
}
Beispiel #6
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;
}
Beispiel #7
0
static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{
	// Error we will return
	int error = 0;

	// Get the watermark filter object
	mlt_filter 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 producer from the filter
	mlt_producer producer = mlt_properties_get_data( properties, "producer", NULL );

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	mlt_service_unlock( MLT_FILTER_SERVICE( filter ) );

	// Process all remaining filters first
	*format = mlt_image_yuv422;
	error = mlt_frame_get_image( frame, image, format, width, height, 0 );

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

		// Create a temporary frame so the original stays in tact.
		mlt_frame a_frame = mlt_frame_clone( frame, 0 );

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

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

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

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

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

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

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

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

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

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

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

		// Close the temporary frames
		mlt_frame_close( a_frame );
		mlt_frame_close( b_frame );
	}

	return error;
}
Beispiel #8
0
int mlt_frame_set_audio( mlt_frame self, void *buffer, mlt_audio_format format, int size, mlt_destructor destructor )
{
	mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "audio_format", format );
	return mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "audio", buffer, size, destructor, NULL );
}
Beispiel #9
0
static void *consumer_thread( void *arg )
{
    // Identify the arg
    consumer_sdl self = arg;

    // Get the consumer
    mlt_consumer consumer = &self->parent;

    // Get the properties
    mlt_properties consumer_props = MLT_CONSUMER_PROPERTIES( consumer );

    // Video thread
    pthread_t thread;

    // internal intialization
    int init_audio = 1;
    int init_video = 1;
    mlt_frame frame = NULL;
    mlt_properties properties = NULL;
    int duration = 0;
    int64_t playtime = 0;
    struct timespec tm = { 0, 100000 };
//	int last_position = -1;

    pthread_mutex_lock( &self->refresh_mutex );
    self->refresh_count = 0;
    pthread_mutex_unlock( &self->refresh_mutex );

    // Loop until told not to
    while( self->running )
    {
        // Get a frame from the attached producer
        frame = mlt_consumer_rt_frame( consumer );

        // Ensure that we have a frame
        if ( frame )
        {
            // Get the frame properties
            properties =  MLT_FRAME_PROPERTIES( frame );

            // Get the speed of the frame
            double speed = mlt_properties_get_double( properties, "_speed" );

            // Get refresh request for the current frame
            int refresh = mlt_properties_get_int( consumer_props, "refresh" );

            // Clear refresh
            mlt_events_block( consumer_props, consumer_props );
            mlt_properties_set_int( consumer_props, "refresh", 0 );
            mlt_events_unblock( consumer_props, consumer_props );

            // Play audio
            init_audio = consumer_play_audio( self, frame, init_audio, &duration );

            // Determine the start time now
            if ( self->playing && init_video )
            {
                // Create the video thread
                pthread_create( &thread, NULL, video_thread, self );

                // Video doesn't need to be initialised any more
                init_video = 0;
            }

            // Set playtime for this frame
            mlt_properties_set_int( properties, "playtime", playtime );

            while ( self->running && speed != 0 && mlt_deque_count( self->queue ) > 15 )
                nanosleep( &tm, NULL );

            // Push this frame to the back of the queue
            if ( self->running && speed )
            {
                pthread_mutex_lock( &self->video_mutex );
                if ( self->is_purge && speed == 1.0 )
                {
                    mlt_frame_close( frame );
                    self->is_purge = 0;
                }
                else
                {
                    mlt_deque_push_back( self->queue, frame );
                    pthread_cond_broadcast( &self->video_cond );
                }
                pthread_mutex_unlock( &self->video_mutex );

                // Calculate the next playtime
                playtime += ( duration * 1000 );
            }
            else if ( self->running )
            {
                pthread_mutex_lock( &self->refresh_mutex );
                if ( ( refresh == 0 && self->refresh_count <= 0 ) || self->refresh_count > 1 )
                {
                    consumer_play_video( self, frame );
                    pthread_cond_wait( &self->refresh_cond, &self->refresh_mutex );
                }
                mlt_frame_close( frame );
                self->refresh_count --;
                pthread_mutex_unlock( &self->refresh_mutex );
            }
            else
            {
                mlt_frame_close( frame );
                frame = NULL;
            }

            // Optimisation to reduce latency
            if ( frame && speed == 1.0 )
            {
                // TODO: disabled due to misbehavior on parallel-consumer
//				if ( last_position != -1 && last_position + 1 != mlt_frame_get_position( frame ) )
//					mlt_consumer_purge( consumer );
//				last_position = mlt_frame_get_position( frame );
            }
            else
            {
                mlt_consumer_purge( consumer );
//				last_position = -1;
            }
        }
    }

    // Kill the video thread
    if ( init_video == 0 )
    {
        pthread_mutex_lock( &self->video_mutex );
        pthread_cond_broadcast( &self->video_cond );
        pthread_mutex_unlock( &self->video_mutex );
        pthread_join( thread, NULL );
    }

    while( mlt_deque_count( self->queue ) )
        mlt_frame_close( mlt_deque_pop_back( self->queue ) );

    self->audio_avail = 0;

    return NULL;
}
Beispiel #10
0
mlt_consumer consumer_sdl_audio_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
{
    // Create the consumer object
    consumer_sdl self = calloc( 1, sizeof( struct consumer_sdl_s ) );

    // If no malloc'd and consumer init ok
    if ( self != NULL && mlt_consumer_init( &self->parent, self, profile ) == 0 )
    {
        // Create the queue
        self->queue = mlt_deque_init( );

        // Get the parent consumer object
        mlt_consumer parent = &self->parent;

        // We have stuff to clean up, so override the close method
        parent->close = consumer_close;

        // get a handle on properties
        mlt_service service = MLT_CONSUMER_SERVICE( parent );
        self->properties = MLT_SERVICE_PROPERTIES( service );

        // Set the default volume
        mlt_properties_set_double( self->properties, "volume", 1.0 );

        // This is the initialisation of the consumer
        pthread_mutex_init( &self->audio_mutex, NULL );
        pthread_cond_init( &self->audio_cond, NULL);
        pthread_mutex_init( &self->video_mutex, NULL );
        pthread_cond_init( &self->video_cond, NULL);

        // Default scaler (for now we'll use nearest)
        mlt_properties_set( self->properties, "rescale", "nearest" );
        mlt_properties_set( self->properties, "deinterlace_method", "onefield" );
        mlt_properties_set_int( self->properties, "top_field_first", -1 );

        // Default buffer for low latency
        mlt_properties_set_int( self->properties, "buffer", 1 );

        // Default audio buffer
        mlt_properties_set_int( self->properties, "audio_buffer", 2048 );

        // Ensure we don't join on a non-running object
        self->joined = 1;

        // Allow thread to be started/stopped
        parent->start = consumer_start;
        parent->stop = consumer_stop;
        parent->is_stopped = consumer_is_stopped;
        parent->purge = consumer_purge;

        // Initialize the refresh handler
        pthread_cond_init( &self->refresh_cond, NULL );
        pthread_mutex_init( &self->refresh_mutex, NULL );
        mlt_events_listen( MLT_CONSUMER_PROPERTIES( parent ), self, "property-changed", ( mlt_listener )consumer_refresh_cb );

        // Return the consumer produced
        return parent;
    }

    // malloc or consumer init failed
    free( self );

    // Indicate failure
    return NULL;
}
Beispiel #11
0
void refresh_image( producer_qimage self, mlt_frame frame, mlt_image_format format, int width, int height )
{
	// Obtain properties of frame and producer
	mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
	mlt_producer producer = &self->parent;

	// Get index and qimage
	int image_idx = refresh_qimage( self, frame );

	// optimization for subsequent iterations on single pictur
	if ( image_idx != self->image_idx || width != self->current_width || height != self->current_height )
		self->current_image = NULL;

	// If we have a qimage and need a new scaled image
	if ( self->qimage && ( !self->current_image || ( format != mlt_image_none && format != mlt_image_glsl && format != self->format ) ) )
	{
		QString interps = mlt_properties_get( properties, "rescale.interp" );
		bool interp = ( interps != "nearest" ) && ( interps != "none" );
		QImage *qimage = static_cast<QImage*>( self->qimage );

		// Note - the original qimage is already safe and ready for destruction
		if ( qimage->depth() == 1 )
		{
			QImage temp = qimage->convertToFormat( QImage::Format_RGB32 );
			delete qimage;
			qimage = new QImage( temp );
			self->qimage = qimage;
		}
		QImage scaled = interp? qimage->scaled( QSize( width, height ) ) :
			qimage->scaled( QSize(width, height), Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
		int has_alpha = scaled.hasAlphaChannel();

		// Store width and height
		self->current_width = width;
		self->current_height = height;

		// Allocate/define image
		int dst_stride = width * ( has_alpha ? 4 : 3 );
		int image_size = dst_stride * ( height + 1 );
		self->current_image = ( uint8_t * )mlt_pool_alloc( image_size );
		self->current_alpha = NULL;
		self->format = has_alpha ? mlt_image_rgb24a : mlt_image_rgb24;

		// Copy the image
		int y = self->current_height + 1;
		uint8_t *dst = self->current_image;
		while ( --y )
		{
			QRgb *src = (QRgb*) scaled.scanLine( self->current_height - y );
			int x = self->current_width + 1;
			while ( --x )
			{
				*dst++ = qRed(*src);
				*dst++ = qGreen(*src);
				*dst++ = qBlue(*src);
				if ( has_alpha ) *dst++ = qAlpha(*src);
				++src;
			}
		}

		// Convert image to requested format
		if ( format != mlt_image_none && format != mlt_image_glsl && format != self->format )
		{
			uint8_t *buffer = NULL;

			// First, set the image so it can be converted when we get it
			mlt_frame_replace_image( frame, self->current_image, self->format, width, height );
			mlt_frame_set_image( frame, self->current_image, image_size, mlt_pool_release );
			self->format = format;

			// get_image will do the format conversion
			mlt_frame_get_image( frame, &buffer, &format, &width, &height, 0 );

			// cache copies of the image and alpha buffers
			if ( buffer )
			{
				image_size = mlt_image_format_size( format, width, height, NULL );
				self->current_image = (uint8_t*) mlt_pool_alloc( image_size );
				memcpy( self->current_image, buffer, image_size );
			}
			if ( ( buffer = mlt_frame_get_alpha_mask( frame ) ) )
			{
				self->current_alpha = (uint8_t*) mlt_pool_alloc( width * height );
				memcpy( self->current_alpha, buffer, width * height );
			}
		}

		// Update the cache
		mlt_cache_item_close( self->image_cache );
		mlt_service_cache_put( MLT_PRODUCER_SERVICE( producer ), "qimage.image", self->current_image, image_size, mlt_pool_release );
		self->image_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.image" );
		self->image_idx = image_idx;
		mlt_cache_item_close( self->alpha_cache );
		self->alpha_cache = NULL;
		if ( self->current_alpha )
		{
			mlt_service_cache_put( MLT_PRODUCER_SERVICE( producer ), "qimage.alpha", self->current_alpha, width * height, mlt_pool_release );
			self->alpha_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.alpha" );
		}
	}

	// Set width/height of frame
	mlt_properties_set_int( properties, "width", self->current_width );
	mlt_properties_set_int( properties, "height", self->current_height );
}
Beispiel #12
0
int refresh_qimage( producer_qimage self, mlt_frame frame )
{
	// Obtain properties of frame and producer
	mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
	mlt_producer producer = &self->parent;
	mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer );

	// Check if user wants us to reload the image
	if ( mlt_properties_get_int( producer_props, "force_reload" ) )
	{
		self->qimage = NULL;
		self->current_image = NULL;
		mlt_properties_set_int( producer_props, "force_reload", 0 );
	}

	// Get the time to live for each frame
	double ttl = mlt_properties_get_int( producer_props, "ttl" );

	// Get the original position of this frame
	mlt_position position = mlt_frame_original_position( frame );
	position += mlt_producer_get_in( producer );

	// Image index
	int image_idx = ( int )floor( ( double )position / ttl ) % self->count;

	int disable_exif = mlt_properties_get_int( producer_props, "disable_exif" );

	if ( !createQApplicationIfNeeded( MLT_PRODUCER_SERVICE(producer) ) )
		return -1;

	if ( image_idx != self->qimage_idx )
		self->qimage = NULL;
	if ( !self->qimage || mlt_properties_get_int( producer_props, "_disable_exif" ) != disable_exif )
	{
		self->current_image = NULL;
		QImage *qimage = new QImage( QString::fromUtf8( mlt_properties_get_value( self->filenames, image_idx ) ) );
		self->qimage = qimage;

		if ( !qimage->isNull( ) )
		{
			// Read the exif value for this file
			if ( !disable_exif )
				qimage = reorient_with_exif( self, image_idx, qimage );

			// Register qimage for destruction and reuse
			mlt_cache_item_close( self->qimage_cache );
			mlt_service_cache_put( MLT_PRODUCER_SERVICE( producer ), "qimage.qimage", qimage, 0, ( mlt_destructor )qimage_delete );
			self->qimage_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.qimage" );
			self->qimage_idx = image_idx;

			// Store the width/height of the qimage
			self->current_width = qimage->width( );
			self->current_height = qimage->height( );

			mlt_events_block( producer_props, NULL );
			mlt_properties_set_int( producer_props, "meta.media.width", self->current_width );
			mlt_properties_set_int( producer_props, "meta.media.height", self->current_height );
			mlt_properties_set_int( producer_props, "_disable_exif", disable_exif );
			mlt_events_unblock( producer_props, NULL );
		}
		else
		{
			delete qimage;
			self->qimage = NULL;
		}
	}

	// Set width/height of frame
	mlt_properties_set_int( properties, "width", self->current_width );
	mlt_properties_set_int( properties, "height", self->current_height );

	return image_idx;
}
Beispiel #13
0
static void refresh_image( producer_pixbuf self, mlt_frame frame, mlt_image_format format, int width, int height )
{
	// Obtain properties of frame and producer
	mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
	mlt_producer producer = &self->parent;

	// Get index and pixbuf
	int current_idx = refresh_pixbuf( self, frame );

	// optimization for subsequent iterations on single picture
	if ( current_idx != self->image_idx || width != self->width || height != self->height )
		self->image = NULL;
	mlt_log_debug( MLT_PRODUCER_SERVICE( producer ), "image %p pixbuf %p idx %d current_idx %d pixbuf_idx %d width %d\n",
		self->image, self->pixbuf, current_idx, self->image_idx, self->pixbuf_idx, width );

	// If we have a pixbuf and we need an image
	if ( self->pixbuf && ( !self->image || ( format != mlt_image_none && format != mlt_image_glsl && format != self->format ) ) )
	{
		char *interps = mlt_properties_get( properties, "rescale.interp" );
		if ( interps ) interps = strdup( interps );
		int interp = GDK_INTERP_BILINEAR;

		if ( !interps ) {
			// Keep bilinear by default
		}
		else if ( strcmp( interps, "nearest" ) == 0 )
			interp = GDK_INTERP_NEAREST;
		else if ( strcmp( interps, "tiles" ) == 0 )
			interp = GDK_INTERP_TILES;
		else if ( strcmp( interps, "hyper" ) == 0 || strcmp( interps, "bicubic" ) == 0 )
			interp = GDK_INTERP_HYPER;
		free( interps );

		// Note - the original pixbuf is already safe and ready for destruction
		pthread_mutex_lock( &g_mutex );
		GdkPixbuf* pixbuf = gdk_pixbuf_scale_simple( self->pixbuf, width, height, interp );

		// Store width and height
		self->width = width;
		self->height = height;

		// Allocate/define image
		int has_alpha = gdk_pixbuf_get_has_alpha( pixbuf );
		int src_stride = gdk_pixbuf_get_rowstride( pixbuf );
		int dst_stride = self->width * ( has_alpha ? 4 : 3 );
		int image_size = dst_stride * ( height + 1 );
		self->image = mlt_pool_alloc( image_size );
		self->alpha = NULL;
		self->format = has_alpha ? mlt_image_rgb24a : mlt_image_rgb24;

		if ( src_stride != dst_stride )
		{
			int y = self->height;
			uint8_t *src = gdk_pixbuf_get_pixels( pixbuf );
			uint8_t *dst = self->image;
			while ( y-- )
			{
				memcpy( dst, src, dst_stride );
				dst += dst_stride;
				src += src_stride;
			}
		}
		else
		{
			memcpy( self->image, gdk_pixbuf_get_pixels( pixbuf ), src_stride * height );
		}
		pthread_mutex_unlock( &g_mutex );

		// Convert image to requested format
		if ( format != mlt_image_none && format != mlt_image_glsl && format != self->format )
		{
			uint8_t *buffer = NULL;

			// First, set the image so it can be converted when we get it
			mlt_frame_replace_image( frame, self->image, self->format, width, height );
			mlt_frame_set_image( frame, self->image, image_size, mlt_pool_release );
			self->format = format;

			// get_image will do the format conversion
			mlt_frame_get_image( frame, &buffer, &format, &width, &height, 0 );

			// cache copies of the image and alpha buffers
			if ( buffer )
			{
				image_size = mlt_image_format_size( format, width, height, NULL );
				self->image = mlt_pool_alloc( image_size );
				memcpy( self->image, buffer, image_size );
			}
			if ( ( buffer = mlt_frame_get_alpha_mask( frame ) ) )
			{
				self->alpha = mlt_pool_alloc( width * height );
				memcpy( self->alpha, buffer, width * height );
			}
		}

		// Update the cache
		mlt_cache_item_close( self->image_cache );
		mlt_service_cache_put( MLT_PRODUCER_SERVICE( producer ), "pixbuf.image", self->image, image_size, mlt_pool_release );
		self->image_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "pixbuf.image" );
		self->image_idx = current_idx;
		mlt_cache_item_close( self->alpha_cache );
		self->alpha_cache = NULL;
		if ( self->alpha )
		{
			mlt_service_cache_put( MLT_PRODUCER_SERVICE( producer ), "pixbuf.alpha", self->alpha, width * height, mlt_pool_release );
			self->alpha_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "pixbuf.alpha" );
		}

		// Finished with pixbuf now
		g_object_unref( pixbuf );
	}

	// Set width/height of frame
	mlt_properties_set_int( properties, "width", self->width );
	mlt_properties_set_int( properties, "height", self->height );
}
Beispiel #14
0
int mlt_frame_get_image( mlt_frame self, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
{
	mlt_properties properties = MLT_FRAME_PROPERTIES( self );
	mlt_get_image get_image = mlt_frame_pop_get_image( self );
	mlt_producer producer = mlt_properties_get_data( properties, "test_card_producer", NULL );
	mlt_image_format requested_format = *format;
	int error = 0;

	if ( get_image )
	{
		mlt_properties_set_int( properties, "image_count", mlt_properties_get_int( properties, "image_count" ) - 1 );
		error = get_image( self, buffer, format, width, height, writable );
		if ( !error && *buffer )
		{
			mlt_properties_set_int( properties, "width", *width );
			mlt_properties_set_int( properties, "height", *height );
			if ( self->convert_image && *buffer && requested_format != mlt_image_none )
				self->convert_image( self, buffer, format, requested_format );
			mlt_properties_set_int( properties, "format", *format );
		}
		else
		{
			// Cause the image to be loaded from test card or fallback (white) below.
			mlt_frame_get_image( self, buffer, format, width, height, writable );
		}
	}
	else if ( mlt_properties_get_data( properties, "image", NULL ) )
	{
		*format = mlt_properties_get_int( properties, "format" );
		*buffer = mlt_properties_get_data( properties, "image", NULL );
		*width = mlt_properties_get_int( properties, "width" );
		*height = mlt_properties_get_int( properties, "height" );
		if ( self->convert_image && *buffer && requested_format != mlt_image_none )
		{
			self->convert_image( self, buffer, format, requested_format );
			mlt_properties_set_int( properties, "format", *format );
		}
	}
	else if ( producer )
	{
		mlt_frame test_frame = NULL;
		mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &test_frame, 0 );
		if ( test_frame )
		{
			mlt_properties test_properties = MLT_FRAME_PROPERTIES( test_frame );
			mlt_properties_set( test_properties, "rescale.interp", mlt_properties_get( properties, "rescale.interp" ) );
			mlt_frame_get_image( test_frame, buffer, format, width, height, writable );
			mlt_properties_set_data( properties, "test_card_frame", test_frame, 0, ( mlt_destructor )mlt_frame_close, NULL );
			mlt_properties_set_double( properties, "aspect_ratio", mlt_frame_get_aspect_ratio( test_frame ) );
// 			mlt_properties_set_data( properties, "image", *buffer, *width * *height * 2, NULL, NULL );
// 			mlt_properties_set_int( properties, "width", *width );
// 			mlt_properties_set_int( properties, "height", *height );
// 			mlt_properties_set_int( properties, "format", *format );
		}
		else
		{
			mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL );
			mlt_frame_get_image( self, buffer, format, width, height, writable );
		}
	}
	else
	{
		register uint8_t *p;
		register uint8_t *q;
		int size = 0;

		*width = *width == 0 ? 720 : *width;
		*height = *height == 0 ? 576 : *height;
		size = *width * *height;

		mlt_properties_set_int( properties, "format", *format );
		mlt_properties_set_int( properties, "width", *width );
		mlt_properties_set_int( properties, "height", *height );
		mlt_properties_set_int( properties, "aspect_ratio", 0 );

		switch( *format )
		{
			case mlt_image_none:
				size = 0;
				*buffer = NULL;
				break;
			case mlt_image_rgb24:
				size *= 3;
				size += *width * 3;
				*buffer = mlt_pool_alloc( size );
				if ( *buffer )
					memset( *buffer, 255, size );
				break;
			case mlt_image_rgb24a:
			case mlt_image_opengl:
				size *= 4;
				size += *width * 4;
				*buffer = mlt_pool_alloc( size );
				if ( *buffer )
					memset( *buffer, 255, size );
				break;
			case mlt_image_yuv422:
				size *= 2;
				size += *width * 2;
				*buffer = mlt_pool_alloc( size );
				p = *buffer;
				q = p + size;
				while ( p != NULL && p != q )
				{
					*p ++ = 235;
					*p ++ = 128;
				}
				break;
			case mlt_image_yuv420p:
				size = size * 3 / 2;
				*buffer = mlt_pool_alloc( size );
				if ( *buffer )
					memset( *buffer, 255, size );
				break;
		}

		mlt_properties_set_data( properties, "image", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL );
		mlt_properties_set_int( properties, "test_image", 1 );
	}

	return error;
}
Beispiel #15
0
static int producer_get_frame( mlt_service service, mlt_frame_ptr frame, int index )
{
	int result = 1;
	mlt_producer self = service != NULL ? service->child : NULL;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	return result;
}
Beispiel #16
0
int mlt_frame_get_audio( mlt_frame self, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
{
	mlt_get_audio get_audio = mlt_frame_pop_audio( self );
	mlt_properties properties = MLT_FRAME_PROPERTIES( self );
	int hide = mlt_properties_get_int( properties, "test_audio" );
	mlt_audio_format requested_format = *format;

	if ( hide == 0 && get_audio != NULL )
	{
		get_audio( self, buffer, format, frequency, channels, samples );
		mlt_properties_set_int( properties, "audio_frequency", *frequency );
		mlt_properties_set_int( properties, "audio_channels", *channels );
		mlt_properties_set_int( properties, "audio_samples", *samples );
		mlt_properties_set_int( properties, "audio_format", *format );
		if ( self->convert_audio && *buffer && requested_format != mlt_audio_none )
			self->convert_audio( self, buffer, format, requested_format );
	}
	else if ( mlt_properties_get_data( properties, "audio", NULL ) )
	{
		*buffer = mlt_properties_get_data( properties, "audio", NULL );
		*format = mlt_properties_get_int( properties, "audio_format" );
		*frequency = mlt_properties_get_int( properties, "audio_frequency" );
		*channels = mlt_properties_get_int( properties, "audio_channels" );
		*samples = mlt_properties_get_int( properties, "audio_samples" );
		if ( self->convert_audio && *buffer && requested_format != mlt_audio_none )
			self->convert_audio( self, buffer, format, requested_format );
	}
	else
	{
		int size = 0;
		*samples = *samples <= 0 ? 1920 : *samples;
		*channels = *channels <= 0 ? 2 : *channels;
		*frequency = *frequency <= 0 ? 48000 : *frequency;
		mlt_properties_set_int( properties, "audio_frequency", *frequency );
		mlt_properties_set_int( properties, "audio_channels", *channels );
		mlt_properties_set_int( properties, "audio_samples", *samples );
		mlt_properties_set_int( properties, "audio_format", *format );

		switch( *format )
		{
			case mlt_image_none:
				size = 0;
				*buffer = NULL;
				break;
			case mlt_audio_s16:
				size = *samples * *channels * sizeof( int16_t );
				break;
			case mlt_audio_s32:
				size = *samples * *channels * sizeof( int32_t );
				break;
			case mlt_audio_float:
				size = *samples * *channels * sizeof( float );
				break;
			default:
				break;
		}
		if ( size )
			*buffer = mlt_pool_alloc( size );
		if ( *buffer )
			memset( *buffer, 0, size );
		mlt_properties_set_data( properties, "audio", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL );
		mlt_properties_set_int( properties, "test_audio", 1 );
	}

	// TODO: This does not belong here
	if ( *format == mlt_audio_s16 && mlt_properties_get( properties, "meta.volume" ) )
	{
		double value = mlt_properties_get_double( properties, "meta.volume" );

		if ( value == 0.0 )
		{
			memset( *buffer, 0, *samples * *channels * 2 );
		}
		else if ( value != 1.0 )
		{
			int total = *samples * *channels;
			int16_t *p = *buffer;
			while ( total -- )
			{
				*p = *p * value;
				p ++;
			}
		}

		mlt_properties_set( properties, "meta.volume", NULL );
	}

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

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

				mlt_producer_set_clones( producer, max_clones );
			}
			else if ( producer != NULL )
			{
				clip_references *refs = mlt_properties_get_data( properties, name, &count );
				for ( i = 0; i < count; i ++ )
				{
					mlt_producer cut = refs[ i ].cut;
					mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( cut ), "_clone", 0 );
				}
				mlt_producer_set_clones( producer, 0 );
			}
		}
		mlt_parser_close( parser );
	}
	return error;
}
Beispiel #18
0
static int get_frame( mlt_producer self, mlt_frame_ptr frame, int index )
{
	mlt_properties properties = MLT_PRODUCER_PROPERTIES(self);
	context cx = mlt_properties_get_data( properties, "context", NULL );

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

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

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

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

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

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

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

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

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

	// Calculate the next timecode
	mlt_producer_prepare_next( self );

	return 0;
}
Beispiel #19
0
static GdkPixbuf* reorient_with_exif( producer_pixbuf self, int image_idx, GdkPixbuf *pixbuf )
{
#ifdef USE_EXIF
	mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( &self->parent );
	ExifData *d = exif_data_new_from_file( mlt_properties_get_value( self->filenames, image_idx ) );
	ExifEntry *entry;
	int exif_orientation = 0;

	/* get orientation and rotate image accordingly if necessary */
	if (d)
	{
		if ( ( entry = exif_content_get_entry ( d->ifd[EXIF_IFD_0], EXIF_TAG_ORIENTATION ) ) )
			exif_orientation = exif_get_short (entry->data, exif_data_get_byte_order (d));

		/* Free the EXIF data */
		exif_data_unref(d);
	}

	// Remember EXIF value, might be useful for someone
	mlt_properties_set_int( producer_props, "_exif_orientation" , exif_orientation );

	if ( exif_orientation > 1 )
	{
		GdkPixbuf *processed = NULL;
		GdkPixbufRotation matrix = GDK_PIXBUF_ROTATE_NONE;

		// Rotate image according to exif data
		switch ( exif_orientation ) {
		  case 2:
			  processed = gdk_pixbuf_flip ( pixbuf, TRUE );
			  break;
		  case 3:
			  matrix = GDK_PIXBUF_ROTATE_UPSIDEDOWN;
			  processed = pixbuf;
			  break;
		  case 4:
			  processed = gdk_pixbuf_flip ( pixbuf, FALSE );
			  break;
		  case 5:
			  matrix = GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE;
			  processed = gdk_pixbuf_flip ( pixbuf, TRUE );
			  break;
		  case 6:
			  matrix = GDK_PIXBUF_ROTATE_CLOCKWISE;
			  processed = pixbuf;
			  break;
		  case 7:
			  matrix = GDK_PIXBUF_ROTATE_CLOCKWISE;
			  processed = gdk_pixbuf_flip ( pixbuf, TRUE );
			  break;
		  case 8:
			  matrix = GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE;
			  processed = pixbuf;
			  break;
		}
		if ( processed )
		{
			pixbuf = gdk_pixbuf_rotate_simple( processed, matrix );
			g_object_unref( processed );
		}
	}
#endif
	return pixbuf;
}