コード例 #1
0
ファイル: mlt_transition.c プロジェクト: jjcare/mlt
double mlt_transition_get_progress_delta( mlt_transition self, mlt_frame frame )
{
	double progress = 0;
	mlt_position in = mlt_transition_get_in( self );
	mlt_position out = mlt_transition_get_out( self );

	if ( out == 0 )
	{
		// If always active, use the frame's producer
		mlt_producer producer = mlt_frame_get_original_producer( frame );
		if ( producer )
		{
			in = mlt_producer_get_in( producer );
			out = mlt_producer_get_out( producer );
		}
	}
	if ( out != 0 )
	{
		mlt_position position = mlt_frame_get_position( frame );
		double length = out - in + 1;
		double x = ( double ) ( position - in ) / length;
		double y = ( double ) ( position + 1 - in ) / length;
		progress = ( y - x ) / 2.0;
	}
	return progress;
}
コード例 #2
0
ファイル: filter_glsl_manager.cpp プロジェクト: jksiezni/mlt
Effect* GlslManager::add_effect( mlt_filter filter, mlt_frame frame, Effect* effect )
{
	Mlt::Producer producer( mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ) );
	EffectChain* chain = (EffectChain*) producer.get_data( "movit chain" );
	chain->add_effect( effect );
	char *unique_id = mlt_properties_get( MLT_FILTER_PROPERTIES(filter), "_unique_id" );
	GlslManager::get_instance()->effect_list( producer ).set( unique_id, effect, 0 );
	return effect;
}
コード例 #3
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;
}
コード例 #4
0
ファイル: filter_dynamictext.c プロジェクト: Metacowboy/mlt
static void get_localfiledate_str( mlt_filter filter, mlt_frame frame, char* text )
{
	mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) );
	mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer );
	char* filename = mlt_properties_get( producer_properties, "resource" );
	struct stat file_info;

	if( !stat( filename, &file_info ) )
	{
		struct tm* time_info = localtime( &(file_info.st_mtime) );
		char date[11] = "";
		strftime( date, 11, "%Y/%m/%d", time_info );
		strncat( text, date, MAX_TEXT_LEN - strlen( text ) - 1);
	}
}
コード例 #5
0
ファイル: mlt_filter.c プロジェクト: mcfrisk/mlt
mlt_position mlt_filter_get_length2( mlt_filter self, mlt_frame frame )
{
	mlt_properties properties = MLT_SERVICE_PROPERTIES( &self->parent );
	mlt_position in = mlt_properties_get_position( properties, "in" );
	mlt_position out = mlt_properties_get_position( properties, "out" );

	if ( out == 0 && frame )
	{
		// If always active, use the frame's producer
		mlt_producer producer = mlt_frame_get_original_producer( frame );
		if ( producer )
		{
			producer = mlt_producer_cut_parent( producer );
			in = mlt_producer_get_in( producer );
			out = mlt_producer_get_out( producer );
		}
	}
	return ( out > 0 ) ? ( out - in + 1 ) : 0;
}
コード例 #6
0
static mlt_frame filter_process( mlt_filter filter, mlt_frame frame )
{
	mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame );
	if( mlt_frame_is_test_card( frame ) ) {
		// The producer does not generate video. This filter will create an
		// image on the producer's behalf.
		mlt_profile profile = mlt_service_profile(
			MLT_PRODUCER_SERVICE( mlt_frame_get_original_producer( frame ) ) );
		mlt_properties_set_int( frame_properties, "progressive", 1 );
		mlt_properties_set_double( frame_properties, "aspect_ratio", mlt_profile_sar( profile ) );
		mlt_properties_set_int( frame_properties, "meta.media.width", profile->width );
		mlt_properties_set_int( frame_properties, "meta.media.height", profile->height );
		// Tell the framework that there really is an image.
		mlt_properties_set_int( frame_properties, "test_image", 0 );
		// Push a callback to create the image.
		mlt_frame_push_get_image( frame, create_image );
	}
	mlt_frame_push_service( frame, filter );
	mlt_frame_push_get_image( frame, filter_get_image );

	return frame;
}
コード例 #7
0
ファイル: mlt_transition.c プロジェクト: jjcare/mlt
double mlt_transition_get_progress( mlt_transition self, mlt_frame frame )
{
	double progress = 0;
	mlt_position in = mlt_transition_get_in( self );
	mlt_position out = mlt_transition_get_out( self );

	if ( out == 0 )
	{
		// If always active, use the frame's producer
		mlt_producer producer = mlt_frame_get_original_producer( frame );
		if ( producer )
		{
			in = mlt_producer_get_in( producer );
			out = mlt_producer_get_out( producer );
		}
	}
	if ( out != 0 )
	{
		mlt_position position = mlt_frame_get_position( frame );
		progress = ( double ) ( position - in ) / ( double ) ( out - in + 1 );
	}
	return progress;
}
コード例 #8
0
ファイル: filter_glsl_manager.cpp プロジェクト: jksiezni/mlt
void GlslManager::unlock_service( mlt_frame frame )
{
	Mlt::Producer producer( mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ) );
	producer.unlock();
}
コード例 #9
0
ファイル: filter_glsl_manager.cpp プロジェクト: jksiezni/mlt
Effect* GlslManager::get_effect( mlt_filter filter, mlt_frame frame )
{
	Mlt::Producer producer( mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ) );
	char *unique_id = mlt_properties_get( MLT_FILTER_PROPERTIES(filter), "_unique_id" );
	return (Effect*) GlslManager::get_instance()->effect_list( producer ).get_data( unique_id );
}
コード例 #10
0
ファイル: filter_dynamictext.c プロジェクト: Metacowboy/mlt
static void get_resource_str( mlt_filter filter, mlt_frame frame, char* text )
{
	mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) );
	mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer );
	strncat( text, mlt_properties_get( producer_properties, "resource" ), MAX_TEXT_LEN - strlen( text ) - 1 );
}
コード例 #11
0
ファイル: mlt_tractor.c プロジェクト: elfring/mlt
static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int track )
{
	mlt_tractor self = parent->child;

	// We only respond to the first track requests
	if ( track == 0 && self->producer != NULL )
	{
		int i = 0;
		int done = 0;
		mlt_frame temp = NULL;
		int count = 0;
		int image_count = 0;

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

		// Try to obtain the multitrack associated to the tractor
		mlt_multitrack multitrack = mlt_properties_get_data( properties, "multitrack", NULL );

		// Or a specific producer
		mlt_producer producer = mlt_properties_get_data( properties, "producer", NULL );

		// Determine whether this tractor feeds to the consumer or stops here
		int global_feed = mlt_properties_get_int( properties, "global_feed" );

		// If we don't have one, we're in trouble...
		if ( multitrack != NULL )
		{
			// The output frame will hold the 'global' data feeds (ie: those which are targetted for the final frame)
			mlt_deque data_queue = mlt_deque_init( );

			// Used to garbage collect all frames
			char label[ 30 ];

			// Get the id of the tractor
			char *id = mlt_properties_get( properties, "_unique_id" );

			// Will be used to store the frame properties object
			mlt_properties frame_properties = NULL;

			// We'll store audio and video frames to use here
			mlt_frame audio = NULL;
			mlt_frame video = NULL;
			mlt_frame first_video = NULL;

			// Temporary properties
			mlt_properties temp_properties = NULL;

			// Get the multitrack's producer
			mlt_producer target = MLT_MULTITRACK_PRODUCER( multitrack );
			mlt_producer_seek( target, mlt_producer_frame( parent ) );
			mlt_producer_set_speed( target, mlt_producer_get_speed( parent ) );

			// We will create one frame and attach everything to it
			*frame = mlt_frame_init( MLT_PRODUCER_SERVICE( parent ) );

			// Get the properties of the frame
			frame_properties = MLT_FRAME_PROPERTIES( *frame );

			// Loop through each of the tracks we're harvesting
			for ( i = 0; !done; i ++ )
			{
				// Get a frame from the producer
				mlt_service_get_frame( self->producer, &temp, i );

				// Get the temporary properties
				temp_properties = MLT_FRAME_PROPERTIES( temp );

				// Pass all unique meta properties from the producer's frame to the new frame
				mlt_properties_lock( temp_properties );
				int props_count = mlt_properties_count( temp_properties );
				int j;
				for ( j = 0; j < props_count; j ++ )
				{
					char *name = mlt_properties_get_name( temp_properties, j );
					if ( !strncmp( name, "meta.", 5 ) && !mlt_properties_get( frame_properties, name ) )
						mlt_properties_set( frame_properties, name, mlt_properties_get_value( temp_properties, j ) );
				}
				mlt_properties_unlock( temp_properties );

				// Copy the format conversion virtual functions
				if ( ! (*frame)->convert_image && temp->convert_image )
					(*frame)->convert_image = temp->convert_image;
				if ( ! (*frame)->convert_audio && temp->convert_audio )
					(*frame)->convert_audio = temp->convert_audio;

				// Check for last track
				done = mlt_properties_get_int( temp_properties, "last_track" );

				// Handle fx only tracks
				if ( mlt_properties_get_int( temp_properties, "fx_cut" ) )
				{
					int hide = ( video == NULL ? 1 : 0 ) | ( audio == NULL ? 2 : 0 );
					mlt_properties_set_int( temp_properties, "hide", hide );
				}

				// We store all frames with a destructor on the output frame
				sprintf( label, "_%s_%d", id, count ++ );
				mlt_properties_set_data( frame_properties, label, temp, 0, ( mlt_destructor )mlt_frame_close, NULL );

				// We want to append all 'final' feeds to the global queue
				if ( !done && mlt_properties_get_data( temp_properties, "data_queue", NULL ) != NULL )
				{
					// Move the contents of this queue on to the output frames data queue
					mlt_deque sub_queue = mlt_properties_get_data( MLT_FRAME_PROPERTIES( temp ), "data_queue", NULL );
					mlt_deque temp = mlt_deque_init( );
					while ( global_feed && mlt_deque_count( sub_queue ) )
					{
						mlt_properties p = mlt_deque_pop_back( sub_queue );
						if ( mlt_properties_get_int( p, "final" ) )
							mlt_deque_push_back( data_queue, p );
						else
							mlt_deque_push_back( temp, p );
					}
					while( mlt_deque_count( temp ) )
						mlt_deque_push_front( sub_queue, mlt_deque_pop_back( temp ) );
					mlt_deque_close( temp );
				}

				// Now do the same with the global queue but without the conditional behaviour
				if ( mlt_properties_get_data( temp_properties, "global_queue", NULL ) != NULL )
				{
					mlt_deque sub_queue = mlt_properties_get_data( MLT_FRAME_PROPERTIES( temp ), "global_queue", NULL );
					while ( mlt_deque_count( sub_queue ) )
					{
						mlt_properties p = mlt_deque_pop_back( sub_queue );
						mlt_deque_push_back( data_queue, p );
					}
				}

				// Pick up first video and audio frames
				if ( !done && !mlt_frame_is_test_audio( temp ) && !( mlt_properties_get_int( temp_properties, "hide" ) & 2 ) )
				{
					// Order of frame creation is starting to get problematic
					if ( audio != NULL )
					{
						mlt_deque_push_front( MLT_FRAME_AUDIO_STACK( temp ), producer_get_audio );
						mlt_deque_push_front( MLT_FRAME_AUDIO_STACK( temp ), audio );
					}
					audio = temp;
				}
				if ( !done && !mlt_frame_is_test_card( temp ) && !( mlt_properties_get_int( temp_properties, "hide" ) & 1 ) )
				{
					if ( video != NULL )
					{
						mlt_deque_push_front( MLT_FRAME_IMAGE_STACK( temp ), producer_get_image );
						mlt_deque_push_front( MLT_FRAME_IMAGE_STACK( temp ), video );
					}
					video = temp;
					if ( first_video == NULL )
						first_video = temp;

					mlt_properties_set_int( MLT_FRAME_PROPERTIES( temp ), "image_count", ++ image_count );
					image_count = 1;
				}
			}

			// Now stack callbacks
			if ( audio != NULL )
			{
				mlt_frame_push_audio( *frame, audio );
				mlt_frame_push_audio( *frame, producer_get_audio );
			}

			if ( video != NULL )
			{
				mlt_properties video_properties = MLT_FRAME_PROPERTIES( first_video );
				mlt_frame_push_service( *frame, video );
				mlt_frame_push_service( *frame, producer_get_image );
				if ( global_feed )
					mlt_properties_set_data( frame_properties, "data_queue", data_queue, 0, NULL, NULL );
				mlt_properties_set_data( video_properties, "global_queue", data_queue, 0, destroy_data_queue, NULL );
				mlt_properties_set_int( frame_properties, "width", mlt_properties_get_int( video_properties, "width" ) );
				mlt_properties_set_int( frame_properties, "height", mlt_properties_get_int( video_properties, "height" ) );
				mlt_properties_pass_list( frame_properties, video_properties, "meta.media.width, meta.media.height" );
				mlt_properties_set_int( frame_properties, "progressive", mlt_properties_get_int( video_properties, "progressive" ) );
				mlt_properties_set_double( frame_properties, "aspect_ratio", mlt_properties_get_double( video_properties, "aspect_ratio" ) );
				mlt_properties_set_int( frame_properties, "image_count", image_count );
				mlt_properties_set_data( frame_properties, "_producer", mlt_frame_get_original_producer( first_video ), 0, NULL, NULL );
			}
			else
			{
				destroy_data_queue( data_queue );
			}

			mlt_frame_set_position( *frame, mlt_producer_frame( parent ) );
			mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "test_audio", audio == NULL );
			mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "test_image", video == NULL );
		}
		else if ( producer != NULL )
		{
			mlt_producer_seek( producer, mlt_producer_frame( parent ) );
			mlt_producer_set_speed( producer, mlt_producer_get_speed( parent ) );
			mlt_service_get_frame( self->producer, frame, track );
		}
		else
		{
			mlt_log( MLT_PRODUCER_SERVICE( parent ), MLT_LOG_ERROR, "tractor without a multitrack!!\n" );
			mlt_service_get_frame( self->producer, frame, track );
		}

		// Prepare the next frame
		mlt_producer_prepare_next( parent );

		// Indicate our found status
		return 0;
	}
	else
	{
		// Generate a test card
		*frame = mlt_frame_init( MLT_PRODUCER_SERVICE( parent ) );
		return 0;
	}
}
コード例 #12
0
ファイル: mlt_frame.c プロジェクト: agpanarin/mlt
unsigned char *mlt_frame_get_waveform( mlt_frame self, int w, int h )
{
	int16_t *pcm = NULL;
	mlt_properties properties = MLT_FRAME_PROPERTIES( self );
	mlt_audio_format format = mlt_audio_s16;
	int frequency = 16000;
	int channels = 2;
	mlt_producer producer = mlt_frame_get_original_producer( self );
	double fps = mlt_producer_get_fps( mlt_producer_cut_parent( producer ) );
	int samples = mlt_sample_calculator( fps, frequency, mlt_frame_get_position( self ) );

	// Increase audio resolution proportional to requested image size
	while ( samples < w )
	{
		frequency += 16000;
		samples = mlt_sample_calculator( fps, frequency, mlt_frame_get_position( self ) );
	}

	// Get the pcm data
	mlt_frame_get_audio( self, (void**)&pcm, &format, &frequency, &channels, &samples );

	// Make an 8-bit buffer large enough to hold rendering
	int size = w * h;
	if ( size <= 0 )
		return NULL;
	unsigned char *bitmap = ( unsigned char* )mlt_pool_alloc( size );
	if ( bitmap != NULL )
		memset( bitmap, 0, size );
	else
		return NULL;
	mlt_properties_set_data( properties, "waveform", bitmap, size, ( mlt_destructor )mlt_pool_release, NULL );

	// Render vertical lines
	int16_t *ubound = pcm + samples * channels;
	int skip = samples / w;
	skip = !skip ? 1 : skip;
	unsigned char gray = 0xFF / skip;
	int i, j, k;

	// Iterate sample stream and along x coordinate
	for ( i = 0; pcm < ubound; i++ )
	{
		// pcm data has channels interleaved
		for ( j = 0; j < channels; j++, pcm++ )
		{
			// Determine sample's magnitude from 2s complement;
			int pcm_magnitude = *pcm < 0 ? ~(*pcm) + 1 : *pcm;
			// The height of a line is the ratio of the magnitude multiplied by
			// the vertical resolution of a single channel
				int height = h * pcm_magnitude / channels / 2 / 32768;
			// Determine the starting y coordinate - left top, right bottom
			int displacement = h * (j * 2 + 1) / channels / 2 - ( *pcm < 0 ? 0 : height );
			// Position buffer pointer using y coordinate, stride, and x coordinate
			unsigned char *p = bitmap + i / skip + displacement * w;

			// Draw vertical line
			for ( k = 0; k < height + 1; k++ )
				if ( *pcm < 0 )
					p[ w * k ] = ( k == 0 ) ? 0xFF : p[ w * k ] + gray;
				else
					p[ w * k ] = ( k == height ) ? 0xFF : p[ w * k ] + gray;
		}
	}

	return bitmap;
}
コード例 #13
0
ファイル: mlt_frame.c プロジェクト: agpanarin/mlt
mlt_frame mlt_frame_clone( mlt_frame self, int is_deep )
{
	mlt_frame new_frame = mlt_frame_init( NULL );
	mlt_properties properties = MLT_FRAME_PROPERTIES( self );
	mlt_properties new_props = MLT_FRAME_PROPERTIES( new_frame );
	void *data, *copy;
	int size;

	mlt_properties_inherit( new_props, properties );

	// Carry over some special data properties for the multi consumer.
	mlt_properties_set_data( new_props, "_producer",
		mlt_frame_get_original_producer( self ), 0, NULL, NULL );
	mlt_properties_set_data( new_props, "movit.convert",
		mlt_properties_get_data( properties, "movit.convert", NULL), 0, NULL, NULL );

	if ( is_deep )
	{
		data = mlt_properties_get_data( properties, "audio", &size );
		if ( data )
		{
			if ( !size )
				size = mlt_audio_format_size( mlt_properties_get_int( properties, "audio_format" ),
					mlt_properties_get_int( properties, "audio_samples" ),
					mlt_properties_get_int( properties, "audio_channels" ) );
			copy = mlt_pool_alloc( size );
			memcpy( copy, data, size );
			mlt_properties_set_data( new_props, "audio", copy, size, mlt_pool_release, NULL );
		}
		data = mlt_properties_get_data( properties, "image", &size );
		if ( data )
		{
			if ( ! size )
				size = mlt_image_format_size( mlt_properties_get_int( properties, "format" ),
					mlt_properties_get_int( properties, "width" ),
					mlt_properties_get_int( properties, "height" ), NULL );
			copy = mlt_pool_alloc( size );
			memcpy( copy, data, size );
			mlt_properties_set_data( new_props, "image", copy, size, mlt_pool_release, NULL );

			data = mlt_properties_get_data( properties, "alpha", &size );
			if ( data )
			{
				if ( ! size )
					size = mlt_properties_get_int( properties, "width" ) *
						mlt_properties_get_int( properties, "height" );
				copy = mlt_pool_alloc( size );
				memcpy( copy, data, size );
				mlt_properties_set_data( new_props, "alpha", copy, size, mlt_pool_release, NULL );
			};
		}
	}
	else
	{
		// This frame takes a reference on the original frame since the data is a shallow copy.
		mlt_properties_inc_ref( properties );
		mlt_properties_set_data( new_props, "_cloned_frame", self, 0,
			(mlt_destructor) mlt_frame_close, NULL );

		// Copy properties
		data = mlt_properties_get_data( properties, "audio", &size );
		mlt_properties_set_data( new_props, "audio", data, size, NULL, NULL );
		data = mlt_properties_get_data( properties, "image", &size );
		mlt_properties_set_data( new_props, "image", data, size, NULL, NULL );
		data = mlt_properties_get_data( properties, "alpha", &size );
		mlt_properties_set_data( new_props, "alpha", data, size, NULL, NULL );
	}

	return new_frame;
}
コード例 #14
0
static int convert_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, mlt_image_format output_format )
{
	// Nothing to do!
	if ( *format == output_format )
		return 0;

	mlt_properties properties = MLT_FRAME_PROPERTIES( frame );

	mlt_log_debug( NULL, "filter_movit_convert: %s -> %s\n",
		mlt_image_format_name( *format ), mlt_image_format_name( output_format ) );

	// Use CPU if glsl not initialized or not supported.
	GlslManager* glsl = GlslManager::get_instance();
	if ( !glsl || !glsl->get_int("glsl_supported" ) )
		return convert_on_cpu( frame, image, format, output_format );

	// Do non-GL image conversions on a CPU-based image converter.
	if ( *format != mlt_image_glsl && output_format != mlt_image_glsl && output_format != mlt_image_glsl_texture )
		return convert_on_cpu( frame, image, format, output_format );

	int error = 0;
	int width = mlt_properties_get_int( properties, "width" );
	int height = mlt_properties_get_int( properties, "height" );
	int img_size = mlt_image_format_size( *format, width, height, NULL );
	mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) );
	mlt_service service = MLT_PRODUCER_SERVICE(producer);
	GlslManager::get_instance()->lock_service( frame );
	EffectChain* chain = GlslManager::get_chain( service );
	MltInput* input = GlslManager::get_input( service );

	if ( !chain || !input ) {
		GlslManager::get_instance()->unlock_service( frame );
		return 2;
	}

	if ( *format != mlt_image_glsl ) {
		bool finalize_chain = false;
		if ( output_format == mlt_image_glsl_texture ) {
			// We might already have a texture from a previous conversion from mlt_image_glsl.
			glsl_texture texture = (glsl_texture) mlt_properties_get_data( properties, "movit.convert.texture", NULL );
			// XXX: requires a special property set on the frame by the app for now
			// because we do not have reliable way to clear the texture property
			// when a downstream filter has changed image.
			if ( texture && mlt_properties_get_int( properties, "movit.convert.use_texture") ) {
				*image = (uint8_t*) &texture->texture;
				mlt_frame_set_image( frame, *image, 0, NULL );
				mlt_properties_set_int( properties, "format", output_format );
				*format = output_format;
				GlslManager::get_instance()->unlock_service( frame );
				return error;
			} else {
				// Use a separate chain to convert image in RAM to OpenGL texture.
				// Use cached chain if available and compatible.
				Mlt::Producer producer( mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ) );
				chain = (EffectChain*) producer.get_data( "movit.convert.chain" );
				input = (MltInput*) producer.get_data( "movit.convert.input" );
				int w = producer.get_int( "movit.convert.width" );
				int h = producer.get_int( "movit.convert.height" );
				mlt_image_format f = (mlt_image_format) producer.get_int( "movit.convert.format" );
				if ( !chain || width != w || height != h || output_format != f ) {
					chain = new EffectChain( width, height );
					input = new MltInput( width, height );
					chain->add_input( input );
					chain->add_effect( new Mlt::VerticalFlip() );
					finalize_chain = true;
					producer.set( "movit.convert.chain", chain, 0, (mlt_destructor) delete_chain );
					producer.set( "movit.convert.input", input, 0 );
					producer.set( "movit.convert.width", width );
					producer.set( "movit.convert.height", height );
					producer.set( "movit.convert.format", output_format );
				}
			}
		}
		if ( *format == mlt_image_rgb24a || *format == mlt_image_opengl ) { 
			input->useFlatInput( chain, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, width, height );
			input->set_pixel_data( *image );
		}
		else if ( *format == mlt_image_rgb24 ) {
			input->useFlatInput( chain, FORMAT_RGB, width, height );
			input->set_pixel_data( *image );
		}
		else if ( *format == mlt_image_yuv420p ) {
			ImageFormat image_format;
			YCbCrFormat ycbcr_format;
			if ( 709 == mlt_properties_get_int( properties, "colorspace" ) ) {
				image_format.color_space = COLORSPACE_REC_709;
				image_format.gamma_curve = GAMMA_REC_709;
				ycbcr_format.luma_coefficients = YCBCR_REC_709;
			} else if ( 576 == mlt_properties_get_int( properties, "height" ) ) {
				image_format.color_space = COLORSPACE_REC_601_625;
				image_format.gamma_curve = GAMMA_REC_601;
				ycbcr_format.luma_coefficients = YCBCR_REC_601;
			} else {
				image_format.color_space = COLORSPACE_REC_601_525;
				image_format.gamma_curve = GAMMA_REC_601;
				ycbcr_format.luma_coefficients = YCBCR_REC_601;
			}
			ycbcr_format.full_range = mlt_properties_get_int( properties, "force_full_luma" );
			ycbcr_format.chroma_subsampling_x = ycbcr_format.chroma_subsampling_y = 2;
			// TODO: make new frame properties set by producers
			ycbcr_format.cb_x_position = ycbcr_format.cr_x_position = 0.0f;
			ycbcr_format.cb_y_position = ycbcr_format.cr_y_position = 0.5f;
			input->useYCbCrInput( chain, image_format, ycbcr_format, width, height );
			input->set_pixel_data( *image );
		}
		else if ( *format == mlt_image_yuv422 ) {
			ImageFormat image_format;
			YCbCrFormat ycbcr_format;
			if ( 709 == mlt_properties_get_int( properties, "colorspace" ) ) {
				image_format.color_space = COLORSPACE_REC_709;
				image_format.gamma_curve = GAMMA_REC_709;
				ycbcr_format.luma_coefficients = YCBCR_REC_709;
			} else if ( 576 == height ) {
				image_format.color_space = COLORSPACE_REC_601_625;
				image_format.gamma_curve = GAMMA_REC_601;
				ycbcr_format.luma_coefficients = YCBCR_REC_601;
			} else {
				image_format.color_space = COLORSPACE_REC_601_525;
				image_format.gamma_curve = GAMMA_REC_601;
				ycbcr_format.luma_coefficients = YCBCR_REC_601;
			}
			ycbcr_format.full_range = mlt_properties_get_int( properties, "force_full_luma" );
			ycbcr_format.chroma_subsampling_x = 2;
			ycbcr_format.chroma_subsampling_y = 1;
			// TODO: make new frame properties set by producers
			ycbcr_format.cb_x_position = ycbcr_format.cr_x_position = 0.0f;
			ycbcr_format.cb_y_position = ycbcr_format.cr_y_position = 0.5f;
			input->useYCbCrInput( chain, image_format, ycbcr_format, width, height );
			
			// convert chunky to planar
			uint8_t* planar = (uint8_t*) mlt_pool_alloc( img_size );
			yuv422_to_yuv422p( *image, planar, width, height );
			input->set_pixel_data( planar );
			mlt_frame_set_image( frame, planar, img_size, mlt_pool_release );
		}
		// Finalize the separate conversion chain if needed.
		if ( finalize_chain )
			chain->finalize();
	}

	if ( output_format != mlt_image_glsl ) {
		glsl_fbo fbo = glsl->get_fbo( width, height );

		if ( output_format == mlt_image_glsl_texture ) {
			glsl_texture texture = glsl->get_texture( width, height, GL_RGBA );

			glBindFramebuffer( GL_FRAMEBUFFER, fbo->fbo );
			check_error();
			glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->texture, 0 );
			check_error();
			glBindFramebuffer( GL_FRAMEBUFFER, 0 );
			check_error();

			GlslManager::render( service, chain, fbo->fbo, width, height );

			glFinish();
			check_error();
			glBindFramebuffer( GL_FRAMEBUFFER, 0 );
			check_error();

			*image = (uint8_t*) &texture->texture;
			mlt_frame_set_image( frame, *image, 0, NULL );
			mlt_properties_set_data( properties, "movit.convert.texture", texture, 0,
				(mlt_destructor) GlslManager::release_texture, NULL );
			mlt_properties_set_int( properties, "format", output_format );
			*format = output_format;
		}
		else {
			// Use a PBO to hold the data we read back with glReadPixels()
			// (Intel/DRI goes into a slow path if we don't read to PBO)
			GLenum gl_format = ( output_format == mlt_image_rgb24a || output_format == mlt_image_opengl )?
				GL_RGBA : GL_RGB;
			img_size = width * height * ( gl_format == GL_RGB? 3 : 4 );
			glsl_pbo pbo = glsl->get_pbo( img_size );
			glsl_texture texture = glsl->get_texture( width, height, gl_format );

			if ( fbo && pbo && texture ) {
				// Set the FBO
				glBindFramebuffer( GL_FRAMEBUFFER, fbo->fbo );
				check_error();
				glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->texture, 0 );
				check_error();
				glBindFramebuffer( GL_FRAMEBUFFER, 0 );
				check_error();

				GlslManager::render( service, chain, fbo->fbo, width, height );
	
				// Read FBO into PBO
				glBindBuffer( GL_PIXEL_PACK_BUFFER_ARB, pbo->pbo );
				check_error();
				glBufferData( GL_PIXEL_PACK_BUFFER_ARB, img_size, NULL, GL_STREAM_READ );
				check_error();
				glReadPixels( 0, 0, width, height, gl_format, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0) );
				check_error();
	
				// Copy from PBO
				uint8_t* buf = (uint8_t*) glMapBuffer( GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY );
				check_error();
				*image = (uint8_t*) mlt_pool_alloc( img_size );
				mlt_frame_set_image( frame, *image, img_size, mlt_pool_release );
				memcpy( *image, buf, img_size );

				if ( output_format == mlt_image_yuv422 || output_format == mlt_image_yuv420p ) {
					*format = mlt_image_rgb24;
					error = convert_on_cpu( frame, image, format, output_format );
				}
	
				// Release PBO and FBO
				glUnmapBuffer( GL_PIXEL_PACK_BUFFER_ARB );
				check_error();
				glBindBuffer( GL_PIXEL_PACK_BUFFER_ARB, 0 );
				check_error();
				glBindFramebuffer( GL_FRAMEBUFFER, 0 );
				check_error();
				glBindTexture( GL_TEXTURE_2D, 0 );
				check_error();
				mlt_properties_set_data( properties, "movit.convert.texture", texture, 0,
					(mlt_destructor) GlslManager::release_texture, NULL);
	
				mlt_properties_set_int( properties, "format", output_format );
				*format = output_format;
			}
			else {
				error = 1;
			}
		}
		if ( fbo ) GlslManager::release_fbo( fbo );
	}
	else {
		mlt_properties_set_int( properties, "format", output_format );
		*format = output_format;
	}
	GlslManager::get_instance()->unlock_service( frame );

	return error;
}
コード例 #15
0
ファイル: filter_avcolour_space.c プロジェクト: wideioltd/mlt
static int convert_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, mlt_image_format output_format )
{
	mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
	int width = mlt_properties_get_int( properties, "width" );
	int height = mlt_properties_get_int( properties, "height" );
	int error = 0;

	if ( *format != output_format )
	{
		mlt_profile profile = mlt_service_profile(
			MLT_PRODUCER_SERVICE( mlt_frame_get_original_producer( frame ) ) );
		int profile_colorspace = profile ? profile->colorspace : 601;
		int colorspace = mlt_properties_get_int( properties, "colorspace" );
		int force_full_luma = 0;
		
		mlt_log_debug( NULL, "[filter avcolor_space] %s -> %s @ %dx%d space %d->%d\n",
			mlt_image_format_name( *format ), mlt_image_format_name( output_format ),
			width, height, colorspace, profile_colorspace );

		int in_fmt = convert_mlt_to_av_cs( *format );
		int out_fmt = convert_mlt_to_av_cs( output_format );
		int size = FFMAX( avpicture_get_size( out_fmt, width, height ),
			mlt_image_format_size( output_format, width, height, NULL ) );
		uint8_t *output = mlt_pool_alloc( size );

		if ( *format == mlt_image_rgb24a || *format == mlt_image_opengl )
		{
			register int len = width * height;
			uint8_t *alpha = mlt_pool_alloc( len );

			if ( alpha )
			{
				// Extract the alpha mask from the RGBA image using Duff's Device
				register uint8_t *s = *image + 3; // start on the alpha component
				register uint8_t *d = alpha;
				register int n = ( len + 7 ) / 8;

				switch ( len % 8 )
				{
					case 0:	do { *d++ = *s; s += 4;
					case 7:		 *d++ = *s; s += 4;
					case 6:		 *d++ = *s; s += 4;
					case 5:		 *d++ = *s; s += 4;
					case 4:		 *d++ = *s; s += 4;
					case 3:		 *d++ = *s; s += 4;
					case 2:		 *d++ = *s; s += 4;
					case 1:		 *d++ = *s; s += 4;
							}
							while ( --n > 0 );
				}
				mlt_frame_set_alpha( frame, alpha, len, mlt_pool_release );
			}
		}

		// Update the output
		if ( !av_convert_image( output, *image, out_fmt, in_fmt, width, height,
								colorspace, profile_colorspace, force_full_luma ) )
		{
			// The new colorspace is only valid if destination is YUV.
			if ( output_format == mlt_image_yuv422 || output_format == mlt_image_yuv420p )
				mlt_properties_set_int( properties, "colorspace", profile_colorspace );
		}
		*image = output;
		*format = output_format;
		mlt_frame_set_image( frame, output, size, mlt_pool_release );
		mlt_properties_set_int( properties, "format", output_format );

		if ( output_format == mlt_image_rgb24a || output_format == mlt_image_opengl )
		{
			register int len = width * height;
			int alpha_size = 0;
			uint8_t *alpha = mlt_frame_get_alpha( frame );
			mlt_properties_get_data( properties, "alpha", &alpha_size );

			if ( alpha && alpha_size >= len )
			{
				// Merge the alpha mask from into the RGBA image using Duff's Device
				register uint8_t *s = alpha;
				register uint8_t *d = *image + 3; // start on the alpha component
				register int n = ( len + 7 ) / 8;

				switch ( len % 8 )
				{
					case 0:	do { *d = *s++; d += 4;
					case 7:		 *d = *s++; d += 4;
					case 6:		 *d = *s++; d += 4;
					case 5:		 *d = *s++; d += 4;
					case 4:		 *d = *s++; d += 4;
					case 3:		 *d = *s++; d += 4;
					case 2:		 *d = *s++; d += 4;
					case 1:		 *d = *s++; d += 4;
							}
							while ( --n > 0 );
				}
			}
		}
	}
	return error;
}