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

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

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

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

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

	return result;
}
Example #2
0
static void add_clock_to_frame( mlt_producer producer, mlt_frame frame, time_info* info )
{
	mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) );
	mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer );
	uint8_t* image = NULL;
	mlt_image_format format = mlt_image_rgb24a;
	int size = 0;
	int width = profile->width;
	int height = profile->height;
	int line_width = LINE_WIDTH_RATIO * (width > height ? height : width) / 100;
	int radius = (width > height ? height : width) / 2;
	char* direction = mlt_properties_get( producer_properties, "direction" );
	int clock_angle = 0;

	mlt_frame_get_image( frame, &image, &format, &width, &height, 1 );

	// Calculate the angle for the clock.
	int frames = info->frames;
	if( !strcmp( direction, "down" ) )
	{
		frames = info->fps - info->frames - 1;
	}
	clock_angle = (frames + 1) * 360 / info->fps;

	draw_clock( image, profile, clock_angle, line_width );
	draw_cross( image, profile, line_width );
	draw_ring( image, profile, ( radius * OUTER_RING_RATIO ) / 100, line_width );
	draw_ring( image, profile, ( radius * INNER_RING_RATIO ) / 100, line_width );

	size = mlt_image_format_size( format, width, height, NULL );
	mlt_frame_set_image( frame, image, size, mlt_pool_release );
}
Example #3
0
static int producerGetImage(mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int /*writable*/) {
    int error = 0;
    mlt_properties properties = MLT_FRAME_PROPERTIES(frame);
    mlt_producer producer = (mlt_producer)mlt_properties_get_data(properties, kWebVfxProducerPropertyName, NULL);
    mlt_properties producer_props = MLT_PRODUCER_PROPERTIES(producer);
    int size;
    int bpp;
    bool hasTransparency = false;
    {
        MLTWebVfx::ServiceLocker locker(MLT_PRODUCER_SERVICE(producer));
        if (!locker.initialize(*width, *height))
        return 1;

        if (mlt_properties_get_int( producer_props, "transparent") ) {
            *format = mlt_image_rgb24a;
            hasTransparency = true;
        }
        else {
            *format = mlt_image_rgb24;
        }
        // Get bpp from image format
        mlt_image_format_size(*format, 0, 0, &bpp);
        size = *width * *height * bpp;
        *buffer = (uint8_t*)mlt_pool_alloc(size);

        // When not using transparency, this will make the background black...
        memset( *buffer, 255, size );
        WebVfx::Image outputImage(*buffer, *width, *height, size, hasTransparency);
        locker.getManager()->render(&outputImage,
                                    mlt_properties_get_position(properties, kWebVfxPositionPropertyName),
                                    mlt_producer_get_length(producer), hasTransparency);
    }
    mlt_frame_set_image(frame, *buffer, size, mlt_pool_release);
    if (hasTransparency) {
        // Create the alpha channel
        int alpha_size = *width * *height;
        uint8_t *alpha = (uint8_t *)mlt_pool_alloc( alpha_size );
        // Initialise the alpha
        memset( alpha, 255, alpha_size );
        mlt_frame_set_alpha(frame, alpha, alpha_size, mlt_pool_release);
    }
    return error;
}
Example #4
0
static int producer_get_image( mlt_frame frame, uint8_t** image, mlt_image_format* format, int* width, int* height, int writable )
{
	mlt_producer producer = mlt_frame_pop_service( frame );
	mlt_frame bg_frame = NULL;
	mlt_frame text_frame = NULL;
	int error = 1;
	int size = 0;
	char* background = mlt_properties_get( MLT_PRODUCER_PROPERTIES( producer ), "background" );
	time_info info;

	mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) );

	get_time_info( producer, frame, &info );

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

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

	if( text_frame )
	{
		mlt_frame_close( text_frame );
	}

	mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) );

	return error;
}
Example #5
0
static int producer_get_image( mlt_frame frame, uint8_t** buffer, mlt_image_format* format, int* width, int* height, int writable )
{
	mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame );
	mlt_producer producer = static_cast<mlt_producer>( mlt_properties_get_data( frame_properties, "_producer_qtext", NULL ) );
	mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer );
	int img_size = 0;
	int alpha_size = 0;
	uint8_t* alpha = NULL;
	QImage* qImg = static_cast<QImage*>( mlt_properties_get_data( producer_properties, "_qimg", NULL ) );

	mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) );

	// Regenerate the qimage if necessary
	if( check_qimage( frame_properties ) == true )
	{
		generate_qimage( frame_properties );
	}

	*format = mlt_image_rgb24a;
	*width = qImg->width();
	*height = qImg->height();

	// Allocate and fill the image buffer
	img_size = mlt_image_format_size( *format, *width, *height, NULL );
	*buffer = static_cast<uint8_t*>( mlt_pool_alloc( img_size ) );
	copy_qimage_to_mlt_image( qImg, *buffer );

	mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) );

	// Allocate and fill the alpha buffer
	alpha_size = *width * *height;
	alpha = static_cast<uint8_t*>( mlt_pool_alloc( alpha_size ) );
	copy_image_to_alpha( *buffer, alpha, *width, *height );

	// Update the frame
	mlt_frame_set_image( frame, *buffer, img_size, mlt_pool_release );
	mlt_frame_set_alpha( frame, alpha, alpha_size, mlt_pool_release );
	mlt_properties_set_int( frame_properties, "width", *width );
	mlt_properties_set_int( frame_properties, "height", *height );

	return 0;
}
Example #6
0
static int get_image(mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable)
{
	mlt_transition transition = mlt_frame_pop_service(frame);
	*format = mlt_frame_pop_service_int(frame);
	int error = mlt_frame_get_image(frame, image, format, width, height, writable);
	if (!error) {
		mlt_properties properties = MLT_FRAME_PROPERTIES(frame);
		mlt_frame clone = mlt_properties_get_data(properties, "mask frame", NULL);
		if (clone) {
			mlt_frame_push_get_image(frame, dummy_get_image);
			mlt_service_lock(MLT_TRANSITION_SERVICE(transition));
			mlt_transition_process(transition, clone, frame);
			mlt_service_unlock(MLT_TRANSITION_SERVICE(transition));
			error = mlt_frame_get_image(clone, image, format, width, height, writable);
			if (!error) {
				int size = mlt_image_format_size(*format, *width, *height, NULL);
				mlt_frame_set_image(frame, *image, size, NULL);
			}
		}
	}
	return error;
}
Example #7
0
static int framebuffer_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{

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

	mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) );

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

	mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) );

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

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

	mlt_frame_set_alpha( frame, alpha_copy, alphasize, mlt_pool_release );

	return 0;
}
Example #8
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;
}
Example #9
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;

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

	// Pop the top of stack now
	mlt_filter filter = mlt_frame_pop_service( frame );
	mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) );

	// Retrieve the aspect ratio
	double aspect_ratio = mlt_deque_pop_back_double( MLT_FRAME_IMAGE_STACK( frame ) );
	double consumer_aspect = mlt_profile_sar( mlt_service_profile( MLT_FILTER_SERVICE( filter ) ) );

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

	// Assign requested width/height from our subordinate
	int owidth = *width;
	int oheight = *height;

	// Check for the special case - no aspect ratio means no problem :-)
	if ( aspect_ratio == 0.0 )
		aspect_ratio = consumer_aspect;

	// Reset the aspect ratio
	mlt_properties_set_double( properties, "aspect_ratio", aspect_ratio );

	// XXX: This is a hack, but it forces the force_full_luma to apply by doing a RGB
	// conversion because range scaling only occurs on YUV->RGB. And we do it here,
	// after the deinterlace filter, which only operates in YUV to avoid a YUV->RGB->YUV->?.
	// Instead, it will go YUV->RGB->?.
	if ( mlt_properties_get_int( properties, "force_full_luma" ) )
		*format = mlt_image_rgb24a;

	// Hmmm...
	char *rescale = mlt_properties_get( properties, "rescale.interp" );
	if ( rescale != NULL && !strcmp( rescale, "none" ) )
		return mlt_frame_get_image( frame, image, format, width, height, writable );

	if ( mlt_properties_get_int( properties, "distort" ) == 0 )
	{
		// Normalise the input and out display aspect
		int normalised_width = profile->width;
		int normalised_height = profile->height;
		int real_width = mlt_properties_get_int( properties, "meta.media.width" );
		int real_height = mlt_properties_get_int( properties, "meta.media.height" );
		if ( real_width == 0 )
			real_width = mlt_properties_get_int( properties, "width" );
		if ( real_height == 0 )
			real_height = mlt_properties_get_int( properties, "height" );
		double input_ar = aspect_ratio * real_width / real_height;
		double output_ar = consumer_aspect * owidth / oheight;
		
// 		fprintf( stderr, "real %dx%d normalised %dx%d output %dx%d sar %f in-dar %f out-dar %f\n",
// 		real_width, real_height, normalised_width, normalised_height, owidth, oheight, aspect_ratio, input_ar, output_ar);

		// Optimised for the input_ar > output_ar case (e.g. widescreen on standard)
		int scaled_width = rint( ( input_ar * normalised_width ) / output_ar );
		int scaled_height = normalised_height;

		// Now ensure that our images fit in the output frame
		if ( scaled_width > normalised_width )
		{
			scaled_width = normalised_width;
			scaled_height = rint( ( output_ar * normalised_height ) / input_ar );
		}

		// Now calculate the actual image size that we want
		owidth = rint( scaled_width * owidth / normalised_width );
		oheight = rint( scaled_height * oheight / normalised_height );

		// Tell frame we have conformed the aspect to the consumer
		mlt_frame_set_aspect_ratio( frame, consumer_aspect );
	}

	mlt_properties_set_int( properties, "distort", 0 );

	// Now pass on the calculations down the line
	mlt_properties_set_int( properties, "resize_width", *width );
	mlt_properties_set_int( properties, "resize_height", *height );

	// If there will be padding, then we need packed image format.
	if ( *format == mlt_image_yuv420p )
	{
		int iwidth = mlt_properties_get_int( properties, "width" );
		int iheight = mlt_properties_get_int( properties, "height" );
		if ( iwidth < owidth || iheight < oheight )
			*format = mlt_image_yuv422;
	}

	// Now get the image
	if ( *format == mlt_image_yuv422 )
		owidth -= owidth % 2;
	error = mlt_frame_get_image( frame, image, format, &owidth, &oheight, writable );

	if ( error == 0 && *image )
	{
		int bpp;
		mlt_image_format_size( *format, owidth, oheight, &bpp );
		*image = frame_resize_image( frame, *width, *height, bpp );
	}

	return error;
}
Example #10
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;
}
Example #11
0
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;
}
Example #12
0
static int get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{
	mlt_frame b_frame = mlt_frame_pop_frame( a_frame );
	mlt_properties properties = MLT_FRAME_PROPERTIES( a_frame );
	mlt_transition transition = MLT_TRANSITION( mlt_frame_pop_service( a_frame ) );
	uint8_t *b_image;
	int window_size = mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( transition ), "window_size" );
	double psnr[3], ssim[3];

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

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

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

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

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

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

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

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

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

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

	return 0;
}
Example #13
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;
}
Example #14
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;
}
Example #15
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;
}
Example #16
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 != self->format ) ) )
	{
		char *interps = mlt_properties_get( properties, "rescale.interp" );
		int interp = 0;
		QImage *qimage = static_cast<QImage*>( self->qimage );

		// QImage has two scaling modes - we'll toggle between them here
		if ( strcmp( interps, "tiles" ) == 0
			|| strcmp( interps, "hyper" ) == 0
			|| strcmp( interps, "bicubic" ) == 0 )
			interp = 1;

		// 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 == 0 ? 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 != 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 );
}
Example #17
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;
}
Example #18
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 */
	mlt_properties properties = MLT_FRAME_PROPERTIES( frame );

	/* Obtain the producer for this frame */
	producer_ktitle self = mlt_properties_get_data( properties, "producer_kdenlivetitle", NULL );
	
	/* Obtain properties of producer */
	mlt_producer producer = &self->parent;
	mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer );
	
	if ( mlt_properties_get_int( properties, "rescale_width" ) > 0 )
		*width = mlt_properties_get_int( properties, "rescale_width" );
	if ( mlt_properties_get_int( properties, "rescale_height" ) > 0 )
		*height = mlt_properties_get_int( properties, "rescale_height" );
	
	mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) );

	/* Allocate the image */
	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( self, frame, *format, *width, *height, mlt_frame_original_position( frame ), 1 );
	}
	else
	{
		drawKdenliveTitle( self, frame, *format, *width, *height, mlt_frame_original_position( frame ), 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" );
	*format = self->format;

	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 );
		// We use height-1 because mlt_image_format_size() uses height + 1.
		// XXX Remove -1 when mlt_image_format_size() is changed.
		memcpy( image_copy, self->current_image,
			mlt_image_format_size( self->format, self->current_width, self->current_height - 1, NULL ) );
		// 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;

		// 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;
	}

	mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) );

	return error;
}
Example #19
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 );
}