Ejemplo n.º 1
0
static int convert_mlt_to_av_cs( mlt_image_format format )
{
	int value = 0;

	switch( format )
	{
		case mlt_image_rgb24:
			value = AV_PIX_FMT_RGB24;
			break;
		case mlt_image_rgb24a:
		case mlt_image_opengl:
			value = AV_PIX_FMT_RGBA;
			break;
		case mlt_image_yuv422:
			value = AV_PIX_FMT_YUYV422;
			break;
		case mlt_image_yuv420p:
			value = AV_PIX_FMT_YUV420P;
			break;
		default:
			mlt_log_error( NULL, "[filter avcolor_space] Invalid format %s\n",
				mlt_image_format_name( format ) );
			break;
	}

	return value;
}
Ejemplo n.º 2
0
int mlt_consumer_init( mlt_consumer self, void *child, mlt_profile profile )
{
	int error = 0;
	memset( self, 0, sizeof( struct mlt_consumer_s ) );
	self->child = child;
	error = mlt_service_init( &self->parent, self );
	if ( error == 0 )
	{
		// Get the properties from the service
		mlt_properties properties = MLT_SERVICE_PROPERTIES( &self->parent );

		// Apply profile to properties
		if ( profile == NULL )
		{
			// Normally the application creates the profile and controls its lifetime
			// This is the fallback exception handling
			profile = mlt_profile_init( NULL );
			mlt_properties properties = MLT_CONSUMER_PROPERTIES( self );
			mlt_properties_set_data( properties, "_profile", profile, 0, (mlt_destructor)mlt_profile_close, NULL );
		}
		apply_profile_properties( self, profile, properties );

		// Default rescaler for all consumers
		mlt_properties_set( properties, "rescale", "bilinear" );

		// Default read ahead buffer size
		mlt_properties_set_int( properties, "buffer", 25 );
		mlt_properties_set_int( properties, "drop_max", 5 );

		// Default audio frequency and channels
		mlt_properties_set_int( properties, "frequency", 48000 );
		mlt_properties_set_int( properties, "channels", 2 );

		// Default of all consumers is real time
		mlt_properties_set_int( properties, "real_time", 1 );

		// Default to environment test card
		mlt_properties_set( properties, "test_card", mlt_environment( "MLT_TEST_CARD" ) );

		// Hmm - default all consumers to yuv422 :-/
		self->format = mlt_image_yuv422;
		mlt_properties_set( properties, "mlt_image_format", mlt_image_format_name( self->format ) );
		mlt_properties_set( properties, "mlt_audio_format", mlt_audio_format_name( mlt_audio_s16 ) );

		mlt_events_register( properties, "consumer-frame-show", ( mlt_transmitter )mlt_consumer_frame_show );
		mlt_events_register( properties, "consumer-frame-render", ( mlt_transmitter )mlt_consumer_frame_render );
		mlt_events_register( properties, "consumer-stopped", NULL );
		mlt_events_listen( properties, self, "consumer-frame-show", ( mlt_listener )on_consumer_frame_show );

		// Register a property-changed listener to handle the profile property -
		// subsequent properties can override the profile
		self->event_listener = mlt_events_listen( properties, self, "property-changed", ( mlt_listener )mlt_consumer_property_changed );

		// Create the push mutex and condition
		pthread_mutex_init( &self->put_mutex, NULL );
		pthread_cond_init( &self->put_cond, NULL );

	}
	return error;
}
Ejemplo n.º 3
0
static void apply_lut( mlt_filter filter, uint8_t* image, mlt_image_format format, int width, int height )
{
	private_data* self = (private_data*)filter->child;
	uint8_t* rlut = malloc( sizeof(self->rlut) );
	uint8_t* glut = malloc( sizeof(self->glut) );
	uint8_t* blut = malloc( sizeof(self->blut) );
	int total = width * height + 1;
	uint8_t* sample = image;

	// Copy the LUT so that we can be frame-thread safe.
	mlt_service_lock( MLT_FILTER_SERVICE( filter ) );
	memcpy( rlut, self->rlut, sizeof(self->rlut) );
	memcpy( glut, self->glut, sizeof(self->glut) );
	memcpy( blut, self->blut, sizeof(self->blut) );
	mlt_service_unlock( MLT_FILTER_SERVICE( filter ) );

	switch( format )
	{
	case mlt_image_rgb24:
		while( --total )
		{
			*sample = rlut[ *sample ];
			sample++;
			*sample = glut[ *sample ];
			sample++;
			*sample = blut[ *sample ];
			sample++;
		}
		break;
	case mlt_image_rgb24a:
		while( --total )
		{
			*sample = rlut[ *sample ];
			sample++;
			*sample = glut[ *sample ];
			sample++;
			*sample = blut[ *sample ];
			sample++;
			sample++; // Skip alpha
		}
		break;
	default:
		mlt_log_error( MLT_FILTER_SERVICE( filter ), "Invalid image format: %s\n", mlt_image_format_name( format ) );
		break;
	}
	free( rlut );
	free( glut );
	free( blut );
}
Ejemplo n.º 4
0
static int setup_sdl_video( consumer_sdl self )
{
	int error = 0;
	int sdl_flags = SDL_WINDOW_RESIZABLE;
	int texture_format = SDL_PIXELFORMAT_YUY2;

	// Skip this if video is disabled.
	int video_off = mlt_properties_get_int( self->properties, "video_off" );
	int preview_off = mlt_properties_get_int( self->properties, "preview_off" );
	if ( video_off || preview_off )
		return error;

	if (!SDL_WasInit(SDL_INIT_VIDEO))
	{
		pthread_mutex_lock( &mlt_sdl_mutex );
		int ret = SDL_Init( SDL_INIT_VIDEO );
		pthread_mutex_unlock( &mlt_sdl_mutex );
		if ( ret < 0 )
		{
			mlt_log_error( MLT_CONSUMER_SERVICE(&self->parent), "Failed to initialize SDL: %s\n", SDL_GetError() );
			return -1;
		}
	}

#if 0 // only yuv422 working currently
	int image_format = mlt_properties_get_int( self->properties, "mlt_image_format" );

	if ( image_format ) switch ( image_format ) {
	case mlt_image_rgb24:
		texture_format = SDL_PIXELFORMAT_RGB24;
		break;
	case mlt_image_rgb24a:
		texture_format = SDL_PIXELFORMAT_ABGR8888;
		break;
	case mlt_image_yuv420p:
		texture_format = SDL_PIXELFORMAT_IYUV;
		break;
	case mlt_image_yuv422:
		texture_format = SDL_PIXELFORMAT_YUY2;
		break;
	default:
		mlt_log_error( MLT_CONSUMER_SERVICE(&self->parent), "Invalid image format %s\n",
			mlt_image_format_name( image_format ) );
		return -1;
	}
#endif

	if ( mlt_properties_get_int( self->properties, "fullscreen" ) )
	{
		self->window_width = self->width;
		self->window_height = self->height;
		sdl_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
		SDL_ShowCursor( SDL_DISABLE );
	}

	pthread_mutex_lock( &mlt_sdl_mutex );
	self->sdl_window = SDL_CreateWindow("MLT", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
		self->window_width, self->window_height, sdl_flags);
	self->sdl_renderer = SDL_CreateRenderer(self->sdl_window, -1, SDL_RENDERER_ACCELERATED);
	if ( self->sdl_renderer )
	{
		self->sdl_texture = SDL_CreateTexture( self->sdl_renderer, texture_format,
			SDL_TEXTUREACCESS_STREAMING, self->window_width, self->window_height );
		if ( self->sdl_texture ) {
			SDL_SetRenderDrawColor( self->sdl_renderer, 0, 0, 0, 255);
		} else {
			mlt_log_error( MLT_CONSUMER_SERVICE(&self->parent), "Failed to create SDL texture: %s\n", SDL_GetError() );
			error = -1;
		}
	} else {
		mlt_log_error( MLT_CONSUMER_SERVICE(&self->parent), "Failed to create SDL renderer: %s\n", SDL_GetError() );
		error = -1;
	}
	pthread_mutex_unlock( &mlt_sdl_mutex );

	return error;
}
Ejemplo n.º 5
0
static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
{
	// Obtain properties of frame
	mlt_properties properties = MLT_FRAME_PROPERTIES( frame );

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

	mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) );

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

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

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

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

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

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

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

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

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

		mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) );

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

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

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

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

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

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

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


	return 0;
}
Ejemplo n.º 6
0
static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
{
	int error = 0;
	
	// Obtain properties of frame and producer
	mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
	producer_qimage self = mlt_properties_get_data( properties, "producer_qimage", NULL );
	mlt_producer producer = &self->parent;

	*width = mlt_properties_get_int( properties, "rescale_width" );
	*height = mlt_properties_get_int( properties, "rescale_height" );

	mlt_service_lock( MLT_PRODUCER_SERVICE( &self->parent ) );

	// Refresh the image
	self->qimage_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.qimage" );
	self->qimage = mlt_cache_item_data( self->qimage_cache, NULL );
	self->image_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.image" );
	self->current_image = mlt_cache_item_data( self->image_cache, NULL );
	self->alpha_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.alpha" );
	self->current_alpha = mlt_cache_item_data( self->alpha_cache, NULL );
	refresh_image( self, frame, *format, *width, *height );

	// Get width and height (may have changed during the refresh)
	*width = mlt_properties_get_int( properties, "width" );
	*height = mlt_properties_get_int( properties, "height" );
	*format = self->format;

	// NB: Cloning is necessary with this producer (due to processing of images ahead of use)
	// The fault is not in the design of mlt, but in the implementation of the qimage producer...
	if ( self->current_image )
	{
		// Clone the image and the alpha
		int image_size = mlt_image_format_size( self->format, self->current_width, self->current_height, NULL );
		uint8_t *image_copy = mlt_pool_alloc( image_size );
		memcpy( image_copy, self->current_image, image_size );
		// Now update properties so we free the copy after
		mlt_frame_set_image( frame, image_copy, image_size, mlt_pool_release );
		// We're going to pass the copy on
		*buffer = image_copy;
		mlt_log_debug( MLT_PRODUCER_SERVICE( &self->parent ), "%dx%d (%s)\n",
			self->current_width, self->current_height, mlt_image_format_name( *format ) );
		// Clone the alpha channel
		if ( self->current_alpha )
		{
			image_copy = mlt_pool_alloc( self->current_width * self->current_height );
			memcpy( image_copy, self->current_alpha, self->current_width * self->current_height );
			mlt_frame_set_alpha( frame, image_copy, self->current_width * self->current_height, mlt_pool_release );
		}
	}
	else
	{
		error = 1;
	}

	// Release references and locks
	mlt_cache_item_close( self->qimage_cache );
	mlt_cache_item_close( self->image_cache );
	mlt_cache_item_close( self->alpha_cache );
	mlt_service_unlock( MLT_PRODUCER_SERVICE( &self->parent ) );

	return error;
}
Ejemplo n.º 7
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 */
	producer_ktitle this = mlt_properties_get_data( properties, "producer_kdenlivetitle", NULL );
	
	/* Obtain properties of producer */
	mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( &this->parent );
	
	*width = mlt_properties_get_int( properties, "rescale_width" );
	*height = mlt_properties_get_int( properties, "rescale_height" );
	
	mlt_service_lock( MLT_PRODUCER_SERVICE( &this->parent ) );

	/* Allocate the image */
	*format = mlt_image_rgb24a;
	mlt_position time = mlt_producer_position( &this->parent ) + mlt_producer_get_in( &this->parent );
	if ( mlt_properties_get_int( producer_props, "force_reload" ) ) {
		if (mlt_properties_get_int( producer_props, "force_reload" ) > 1) read_xml(producer_props);
		mlt_properties_set_int( producer_props, "force_reload", 0 );
		drawKdenliveTitle( this, frame, *width, *height, time, 1);
	}
	else drawKdenliveTitle( this, frame, *width, *height, time, 0);

	// Get width and height (may have changed during the refresh)
	*width = mlt_properties_get_int( properties, "width" );
	*height = mlt_properties_get_int( properties, "height" );
		
	if ( this->current_image )
	{
		// Clone the image and the alpha
		int image_size = this->current_width * ( this->current_height ) * 4;
		uint8_t *image_copy = mlt_pool_alloc( image_size );
		memcpy( image_copy, this->current_image, image_size );
		// Now update properties so we free the copy after
		mlt_frame_set_image( frame, image_copy, image_size, mlt_pool_release );
		// We're going to pass the copy on
		*buffer = image_copy;		

		mlt_log_debug( MLT_PRODUCER_SERVICE( &this->parent ), "width:%d height:%d %s\n", *width, *height, mlt_image_format_name( *format ) );
	}

	mlt_service_unlock( MLT_PRODUCER_SERVICE( &this->parent ) );

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

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

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

	int left    = mlt_properties_get_int( properties, "crop.left" );
	int right   = mlt_properties_get_int( properties, "crop.right" );
	int top     = mlt_properties_get_int( properties, "crop.top" );
	int bottom  = mlt_properties_get_int( properties, "crop.bottom" );

	// Request the image at its original resolution
	if ( left || right || top || bottom )
	{
		mlt_properties_set_int( properties, "rescale_width", mlt_properties_get_int( properties, "crop.original_width" ) );
		mlt_properties_set_int( properties, "rescale_height", mlt_properties_get_int( properties, "crop.original_height" ) );
	}

	// Now get the image
	error = mlt_frame_get_image( frame, image, format, width, height, writable );

	int owidth  = *width - left - right;
	int oheight = *height - top - bottom;
	owidth = owidth < 0 ? 0 : owidth;
	oheight = oheight < 0 ? 0 : oheight;

	if ( ( owidth != *width || oheight != *height ) &&
		error == 0 && *image != NULL && owidth > 0 && oheight > 0 )
	{
		int bpp;

		// Subsampled YUV is messy and less precise.
		if ( *format == mlt_image_yuv422 && frame->convert_image )
		{
			mlt_image_format requested_format = mlt_image_rgb24;
			frame->convert_image( frame, image, format, requested_format );
		}
	
		mlt_log_debug( NULL, "[filter crop] %s %dx%d -> %dx%d\n", mlt_image_format_name(*format),
				 *width, *height, owidth, oheight);

		// Provides a manual override for misreported field order
		if ( mlt_properties_get( properties, "meta.top_field_first" ) )
		{
			mlt_properties_set_int( properties, "top_field_first", mlt_properties_get_int( properties, "meta.top_field_first" ) );
			mlt_properties_set_int( properties, "meta.top_field_first", 0 );
		}

		if ( top % 2 )
			mlt_properties_set_int( properties, "top_field_first", !mlt_properties_get_int( properties, "top_field_first" ) );
		
		// Create the output image
		int size = mlt_image_format_size( *format, owidth, oheight, &bpp );
		uint8_t *output = mlt_pool_alloc( size );
		if ( output )
		{
			// Call the generic resize
			crop( *image, output, bpp, *width, *height, left, right, top, bottom );

			// Now update the frame
			mlt_frame_set_image( frame, output, size, mlt_pool_release );
			*image = output;
		}

		// We should resize the alpha too
		uint8_t *alpha = mlt_frame_get_alpha_mask( frame );
		int alpha_size = 0;
		mlt_properties_get_data( properties, "alpha", &alpha_size );
		if ( alpha && alpha_size >= ( *width * *height ) )
		{
			uint8_t *newalpha = mlt_pool_alloc( owidth * oheight );
			if ( newalpha )
			{
				crop( alpha, newalpha, 1, *width, *height, left, right, top, bottom );
				mlt_frame_set_alpha( frame, newalpha, owidth * oheight, mlt_pool_release );
			}
		}
		*width = owidth;
		*height = oheight;
	}

	return error;
}
Ejemplo n.º 9
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;
}
Ejemplo n.º 10
0
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;
}
Ejemplo n.º 11
0
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 )
	{
		int colorspace = mlt_properties_get_int( properties, "colorspace" );
		int force_full_luma = -1;
		
		mlt_log_debug( NULL, "[filter avcolor_space] %s -> %s @ %dx%d space %d\n",
			mlt_image_format_name( *format ), mlt_image_format_name( output_format ),
			width, height, 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 ( *format == mlt_image_yuv422 && mlt_properties_get( properties, "force_full_luma" )
		     && ( output_format == mlt_image_rgb24 || output_format == mlt_image_rgb24a ) )
		{
			// By removing the frame property we only permit the luma to skip scaling once.
			// Thereafter, we let swscale scale the luma range as it pleases since it seems
			// we do not have control over the RGB to YUV conversion.
			force_full_luma = mlt_properties_get_int( properties, "force_full_luma" );			
			mlt_properties_set( properties, "force_full_luma", NULL );
		}
		av_convert_image( output, *image, out_fmt, in_fmt, width, height, colorspace, force_full_luma );
		*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_mask( 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;
}