예제 #1
0
void mlt_cache_put_frame( mlt_cache cache, mlt_frame frame )
{
	pthread_mutex_lock( &cache->mutex );
	mlt_frame *hit = shuffle_get_frame( cache, mlt_frame_original_position( frame ) );
	mlt_frame *alt = (mlt_frame*) ( cache->current == cache->A ? cache->B : cache->A );

	// add the frame to the cache
	if ( hit )
	{
		// release the old data
		mlt_frame_close( *hit );
		// the MRU end gets the updated data
		hit = &alt[ cache->count - 1 ];
	}
	else if ( cache->count < cache->size )
	{
		// more room in cache, add it to MRU end
		hit = &alt[ cache->count++ ];
	}
	else
	{
		// release the entry at the LRU end
		mlt_frame_close( cache->current[0] );

		// The MRU end gets the new item
		hit = &alt[ cache->count - 1 ];
	}
	*hit = mlt_frame_clone( frame, 1 );
	mlt_log( NULL, MLT_LOG_DEBUG, "%s: put %d = %p\n", __FUNCTION__, cache->count - 1, frame );

	// swap the current array
	cache->current = (void**) alt;
	cache->is_frames = 1;
	pthread_mutex_unlock( &cache->mutex );
}
예제 #2
0
static void get_time_info( mlt_producer producer, mlt_frame frame, time_info* info )
{
	mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer );
	mlt_position position = mlt_frame_original_position( frame );

	info->fps = ceil( mlt_producer_get_fps( producer ) );

	char* direction = mlt_properties_get( producer_properties, "direction" );
	if( !strcmp( direction, "down" ) )
	{
		mlt_position length = mlt_properties_get_int( producer_properties, "length" );
		info->position = length - 1 - position;
	}
	else
	{
		info->position = position;
	}

	char* tc_str = NULL;
	if( mlt_properties_get_int( producer_properties, "drop" ) )
	{
		tc_str = mlt_properties_frames_to_time( producer_properties, info->position, mlt_time_smpte_df );
	}
	else
	{
		tc_str = mlt_properties_frames_to_time( producer_properties, info->position, mlt_time_smpte_ndf );
	}
	sscanf( tc_str, "%02d:%02d:%02d%c%d", &info->hours, &info->minutes, &info->seconds, &info->sep, &info->frames );
}
예제 #3
0
int frame_cache_put_frame( frame_cache self, mlt_frame frame )
{
	if ( self == NULL )
		return 1;

	mlt_position frame_position = mlt_frame_original_position( frame );
	// We actually need to insert frame into cache
	if ( frame_cache_frame_index( self, frame_position ) == -1 )
	{
		if ( self->frames_total > 0 )
		{
			mlt_frame first_frame = self->frames[ self->start_pos ];
			mlt_position first_frame_position = mlt_frame_original_position( first_frame );
			mlt_position last_frame_position = first_frame_position + self->frames_total - 1;
			// We're trying to insert next frame (in sequence), so no need to delete previous ones
			if ( frame_position == last_frame_position + 1 )
			{
				// Append new frame at the end of circular buffer
				if ( self->frames_total < self->size )
				{
					size_t index = ( self->start_pos + self->frames_total ) % self->size;
					self->frames[ index ] = frame;
					self->frames_total += 1;
				}
				// We need to throw out the earliest frame
				else
				{
					self->frames[ self->start_pos ] = frame;
					self->start_pos = ( self->start_pos + 1 ) % self->size;
				}
			}
			// We're inserting frame that is not in cache, and is not next in sequence
			else
			{
				frame_cache_purge( self );
				self->frames[ self->start_pos ] = frame;
				self->frames_total += 1;
			}
		}
		else
		{
			self->frames[ self->start_pos ] = frame;
			self->frames_total += 1;
		}
	}
	return 0;
}
예제 #4
0
static mlt_frame* shuffle_get_frame( mlt_cache cache, mlt_position position )
{
	int i = cache->count;
	int j = cache->count - 1;
	mlt_frame *hit = NULL;
	mlt_frame *alt = (mlt_frame*) ( cache->current == cache->A ? cache->B : cache->A );

	if ( cache->count > 0 && cache->count < cache->size )
	{
		// first determine if we have a hit
		while ( i-- && !hit )
		{
			mlt_frame *o = (mlt_frame*) &cache->current[ i ];
			if ( mlt_frame_original_position( *o ) == position )
				hit = o;
		}
		// if there was no hit, we will not be shuffling out an entry
		// and are still filling the cache
		if ( !hit )
			++j;
		// reset these
		i = cache->count;
		hit = NULL;
	}

	// shuffle the existing entries to the alternate array
	while ( i-- )
	{
		mlt_frame *o = (mlt_frame*) &cache->current[ i ];

		if ( !hit && mlt_frame_original_position( *o ) == position )
		{
			hit = o;
		}
		else if ( j > 0 )
		{
			alt[ --j ] = *o;
// 			mlt_log( NULL, MLT_LOG_DEBUG, "%s: shuffle %d = %p\n", __FUNCTION__, j, alt[j] );
		}
	}
	return hit;
}
예제 #5
0
mlt_position frame_cache_earliest_frame_position( frame_cache self )
{
	if ( self == NULL )
		return FRAME_CACHE_INVALID_POSITION;

	if ( self->frames_total == 0 )
		return FRAME_CACHE_INVALID_POSITION;

	mlt_frame earliest_frame = self->frames[ self->start_pos ];

	return mlt_frame_original_position( earliest_frame );
}
예제 #6
0
mlt_position frame_cache_latest_frame_position( frame_cache self )
{
	if ( self == NULL )
		return FRAME_CACHE_INVALID_POSITION;

	if ( self->frames_total == 0 )
		return FRAME_CACHE_INVALID_POSITION;

	mlt_frame latest_frame =
		self->frames[ ( self->start_pos + self->frames_total - 1 ) % self->size ];

	return mlt_frame_original_position( latest_frame );
}
예제 #7
0
static int filter_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
{
	mlt_filter filter = mlt_frame_pop_audio( frame );
	private_data* pdata = (private_data*)filter->child;
	mlt_position o_pos = mlt_frame_original_position( frame );

	// Get the producer's audio
	*format = mlt_audio_f32le;
	mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples );

	mlt_service_lock( MLT_FILTER_SERVICE( filter ) );

	if( abs( o_pos - pdata->prev_o_pos ) > 1 )
	{
		// Assume this is a new clip and restart
		// Use original position so that transitions between clips are detected.
		pdata->reset = 1;
		mlt_log_info( MLT_FILTER_SERVICE( filter ), "Reset. Old Pos: %d\tNew Pos: %d\n", pdata->prev_o_pos, o_pos );
	}

	check_for_reset( filter, *channels, *frequency );

	if( o_pos != pdata->prev_o_pos )
	{
		// Only analyze the audio is the producer is not paused.
		analyze_audio( filter, *buffer, *samples, *frequency );
	}

	double start_coeff = pdata->start_gain > -90.0 ? pow(10.0, pdata->start_gain / 20.0) : 0.0;
	double end_coeff = pdata->end_gain > -90.0 ? pow(10.0, pdata->end_gain / 20.0) : 0.0;
	double coeff_factor = pow( (end_coeff / start_coeff), 1.0 / (double)*samples );
	double coeff = start_coeff;
	float* p = *buffer;
	int s = 0;
	int c = 0;
	for( s = 0; s < *samples; s++ )
	{
		coeff = coeff * coeff_factor;
		for ( c = 0; c < *channels; c++ )
		{
			*p = *p * coeff;
			p++;
		}
	}

	pdata->prev_o_pos = o_pos;

	mlt_service_unlock( MLT_FILTER_SERVICE( filter ) );

	return 0;
}
예제 #8
0
static ssize_t frame_cache_frame_index( frame_cache self, mlt_position position )
{
	if ( self->frames_total == 0 )
		return -1;

	mlt_frame first_frame = self->frames[ self->start_pos ];
	mlt_position first_frame_position = mlt_frame_original_position( first_frame );
	mlt_position last_frame_position = first_frame_position + self->frames_total - 1;
	if ( position >= first_frame_position && position <= last_frame_position )
	{
		int offset = position - first_frame_position;
		return ( self->start_pos + offset ) % self->size;
	}
	return -1;
}
예제 #9
0
int refresh_qimage( producer_qimage self, mlt_frame frame )
{
	// Obtain properties of frame and producer
	mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
	mlt_producer producer = &self->parent;
	mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer );

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

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

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

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

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

	int disable_exif = mlt_properties_get_int( producer_props, "disable_exif" );
	
	
	if ( app == NULL ) 
	{
		if ( qApp ) 
		{
			app = qApp;
		}
		else 
		{
#ifdef linux
			if ( getenv("DISPLAY") == 0 )
			{
				mlt_log_panic( MLT_PRODUCER_SERVICE( producer ), "Error, cannot render titles without an X11 environment.\nPlease either run melt from an X session or use a fake X server like xvfb:\nxvfb-run -a melt (...)\n" );
				return -1;
			}
#endif
			int argc = 1;
			char* argv[1];
			argv[0] = (char*) "xxx";
			app = new QApplication( argc, argv );
			const char *localename = mlt_properties_get_lcnumeric( MLT_SERVICE_PROPERTIES( MLT_PRODUCER_SERVICE( producer ) ) );
			QLocale::setDefault( QLocale( localename ) );
		}
	}

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

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

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

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

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

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

	return image_idx;
}
예제 #10
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;
}
예제 #11
0
static int producer_get_audio( mlt_frame frame, int16_t** buffer, mlt_audio_format* format, int* frequency, int* channels, int* samples )
{
	mlt_producer producer = (mlt_producer)mlt_frame_pop_audio( frame );
	mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer );
	char* sound = mlt_properties_get( producer_properties, "sound" );
	double fps = mlt_producer_get_fps( producer );
	mlt_position position = mlt_frame_original_position( frame );
	int size = 0;
	int do_beep = 0;
	time_info info;

	if( fps == 0 ) fps = 25;

	// Correct the returns if necessary
	*format = mlt_audio_float;
	*frequency = *frequency <= 0 ? 48000 : *frequency;
	*channels = *channels <= 0 ? 2 : *channels;
	*samples = *samples <= 0 ? mlt_sample_calculator( fps, *frequency, position ) : *samples;

	// Allocate the buffer
	size = *samples * *channels * sizeof( float );
	*buffer = mlt_pool_alloc( size );

	mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) );

	get_time_info( producer, frame, &info );

	// Determine if this should be a tone or silence.
	if( strcmp( sound, "none") )
	{
		if( !strcmp( sound, "2pop" ) )
		{
			mlt_position out = mlt_properties_get_int( producer_properties, "out" );
			mlt_position frames = out - position;

			if( frames == ( info.fps * 2 ) )
			{
				do_beep = 1;
			}
		}
		else if( !strcmp( sound, "frame0" ) )
		{
			if( info.frames == 0 )
			{
				do_beep = 1;
			}
		}
	}

	if( do_beep )
	{
		fill_beep( producer_properties, (float*)*buffer, *frequency, *channels, *samples );
	}
	else
	{
		// Fill silence.
		memset( *buffer, 0, size );
	}

	mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) );

	// Set the buffer for destruction
	mlt_frame_set_audio( frame, *buffer, *format, size, mlt_pool_release );
	return 0;
}
예제 #12
0
파일: qimage_wrapper.cpp 프로젝트: aib/mlt
int refresh_qimage( producer_qimage self, mlt_frame frame )
{
	// Obtain properties of frame and producer
	mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
	mlt_producer producer = &self->parent;
	mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer );

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		}
		pthread_mutex_unlock( &g_mutex );
	}

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

	return current_idx;
}