Ejemplo n.º 1
0
static void cache_object_close( mlt_cache cache, void *object, void* data )
{
	char key[19];

	if ( cache->is_frames )
	{
		// Frame caches are easy - just close the object as mlt_frame.
		mlt_frame_close( object );
		return;
	}

	// Fetch the cache item from the active list by its owner's address
	sprintf( key, "%p", object );
	mlt_cache_item item = mlt_properties_get_data( cache->active, key, NULL );
	if ( item )
	{
		mlt_log( NULL, MLT_LOG_DEBUG, "%s: item %p object %p data %p refcount %d\n", __FUNCTION__,
			item, item->object, item->data, item->refcount );
		if ( item->destructor && --item->refcount <= 0 )
		{
			// Destroy the data object
			item->destructor( item->data );
			item->data = NULL;
			item->destructor = NULL;
			// Do not dispose of the cache item because it could likely be used
			// again.
		}
	}

	// Fetch the cache item from the garbage collection by its data address
	if ( data )
	{
		sprintf( key, "%p", data );
		item = mlt_properties_get_data( cache->garbage, key, NULL );
		if ( item )
		{
			mlt_log( NULL, MLT_LOG_DEBUG, "collecting garbage item %p object %p data %p refcount %d\n",
				item, item->object, item->data, item->refcount );
			if ( item->destructor && --item->refcount <= 0 )
			{
				item->destructor( item->data );
				item->data = NULL;
				item->destructor = NULL;
				// We do not need the garbage-collected cache item
				mlt_properties_set_data( cache->garbage, key, NULL, 0, NULL, NULL );
			}
		}
	}
}
Ejemplo n.º 2
0
int mlt_consumer_stop( mlt_consumer self )
{
	// Get the properies
	mlt_properties properties = MLT_CONSUMER_PROPERTIES( self );

	// Just in case...
	mlt_log( MLT_CONSUMER_SERVICE( self ), MLT_LOG_DEBUG, "stopping put waiting\n" );
	pthread_mutex_lock( &self->put_mutex );
	self->put_active = 0;
	pthread_cond_broadcast( &self->put_cond );
	pthread_mutex_unlock( &self->put_mutex );

	// Stop the consumer
	mlt_log( MLT_CONSUMER_SERVICE( self ), MLT_LOG_DEBUG, "stopping consumer\n" );
	
	// Cancel the read ahead threads
	self->ahead = 0;
	if ( self->started )
	{
		// Unblock the consumer calling mlt_consumer_rt_frame
		pthread_mutex_lock( &self->queue_mutex );
		pthread_cond_broadcast( &self->queue_cond );
		pthread_mutex_unlock( &self->queue_mutex );		
	}
	
	// Invoke the child callback
	if ( self->stop != NULL )
		self->stop( self );

	// Check if the user has requested real time or not and stop if necessary
	mlt_log( MLT_CONSUMER_SERVICE( self ), MLT_LOG_DEBUG, "stopping read_ahead\n" );
	if ( abs( self->real_time ) == 1 )
		consumer_read_ahead_stop( self );
	else if ( abs( self->real_time ) > 1 )
		consumer_work_stop( self );

	// Kill the test card
	mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL );

	// Check and run a post command
	if ( mlt_properties_get( properties, "post" ) )
		if (system( mlt_properties_get( properties, "post" ) ) == -1 )
			mlt_log( MLT_CONSUMER_SERVICE( self ), MLT_LOG_ERROR, "system(%s) failed!\n", mlt_properties_get( properties, "post" ) );

	mlt_log( MLT_CONSUMER_SERVICE( self ), MLT_LOG_DEBUG, "stopped\n" );

	return 0;
}
Ejemplo n.º 3
0
Archivo: mlt_cache.c Proyecto: rayl/MLT
mlt_cache_item mlt_cache_get( mlt_cache cache, void *object )
{
    mlt_cache_item result = NULL;
    pthread_mutex_lock( &cache->mutex );
    void **hit = shuffle_get_hit( cache, object );
    void **alt = cache->current == cache->A ? cache->B : cache->A;

    if ( hit )
    {
        // copy the hit to the MRU end
        alt[ cache->count - 1 ] = *hit;
        hit = &alt[ cache->count - 1 ];

        char key[19];
        sprintf( key, "%p", *hit );
        result = mlt_properties_get_data( cache->active, key, NULL );
        if ( result && result->data )
            result->refcount++;
        mlt_log( NULL, MLT_LOG_DEBUG, "%s: get %d = %p, %p\n", __FUNCTION__, cache->count - 1, *hit, result->data );

        // swap the current array
        cache->current = alt;
    }
    pthread_mutex_unlock( &cache->mutex );

    return result;
}
Ejemplo n.º 4
0
mlt_repository mlt_repository_init( const char *directory )
{
	// Safety check
	if ( directory == NULL || strcmp( directory, "" ) == 0 )
		return NULL;

	// Construct the repository
	mlt_repository self = calloc( 1, sizeof( struct mlt_repository_s ));
	mlt_properties_init( &self->parent, self );
	self->consumers = mlt_properties_new();
	self->filters = mlt_properties_new();
	self->producers = mlt_properties_new();
	self->transitions = mlt_properties_new();

	// Get the directory list
	mlt_properties dir = mlt_properties_new();
	int count = mlt_properties_dir_list( dir, directory, NULL, 0 );
	int i;

	// Iterate over files
	for ( i = 0; i < count; i++ )
	{
		int flags = RTLD_NOW;
		const char *object_name = mlt_properties_get_value( dir, i);

		// Very temporary hack to allow the quicktime plugins to work
		// TODO: extend repository to allow this to be used on a case by case basis
		if ( strstr( object_name, "libmltkino" ) )
			flags |= RTLD_GLOBAL;

		// Open the shared object
		void *object = dlopen( object_name, flags );
		if ( object != NULL )
		{
			// Get the registration function
			mlt_repository_callback symbol_ptr = dlsym( object, "mlt_register" );

			// Call the registration function
			if ( symbol_ptr != NULL )
			{
				symbol_ptr( self );

				// Register the object file for closure
				mlt_properties_set_data( &self->parent, object_name, object, 0, ( mlt_destructor )dlclose, NULL );
			}
			else
			{
				dlclose( object );
			}
		}
		else if ( strstr( object_name, "libmlt" ) )
		{
			mlt_log( NULL, MLT_LOG_WARNING, "%s: failed to dlopen %s\n  (%s)\n", __FUNCTION__, object_name, dlerror() );
		}
	}

	mlt_properties_close( dir );

	return self;
}
Ejemplo n.º 5
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 );
}
Ejemplo n.º 6
0
int ServiceManager::render(WebVfx::Image* outputImage, mlt_position position, mlt_position length, bool hasAlpha)
{
    double time = length > 0 ? position / (double)length : 0;

    parameters->setPositionAndLength(position, length);

    if (mlt_properties_get_int(MLT_SERVICE_PROPERTIES(service), "_reload")) {
        mlt_properties_set_int(MLT_SERVICE_PROPERTIES(service), "_reload", 0);
        effects->reload();
    }

    // Produce any extra images
    if (imageProducers) {
        for (std::vector<ImageProducer*>::iterator it = imageProducers->begin();
             it != imageProducers->end(); it++) {
            ImageProducer* imageProducer = *it;
            if (imageProducer && imageProducer->isPositionValid(position)) {
                WebVfx::Image extraImage =
                    imageProducer->produceImage(position,
                                                outputImage->width(),
                                                outputImage->height(),
                                                hasAlpha);
                if (extraImage.isNull()) {
                    mlt_log(service, MLT_LOG_ERROR, "WebVfx failed to produce image for name %s\n", imageProducer->getName().toLatin1().constData());
                    return 1;
                }
                effects->setImage(imageProducer->getName(), &extraImage);
            }
        }
    }

    return !effects->render(time, outputImage);
}
Ejemplo n.º 7
0
void mlt_producer_close( mlt_producer self )
{
	if ( self != NULL && mlt_properties_dec_ref( MLT_PRODUCER_PROPERTIES( self ) ) <= 0 )
	{
		self->parent.close = NULL;

		if ( self->close != NULL )
		{
			self->close( self->close_object );
		}
		else
		{
			int destroy = mlt_producer_is_cut( self );

#if _MLT_PRODUCER_CHECKS_ == 1
			// Show debug info
			mlt_properties_debug( MLT_PRODUCER_PROPERTIES( self ), "Producer closing", stderr );
#endif

#ifdef _MLT_PRODUCER_CHECKS_
			// Show current stats - these should match when the app is closed
			mlt_log( MLT_PRODUCER_SERVICE( self ), MLT_LOG_DEBUG, "Producers created %d, destroyed %d\n", producers_created, ++producers_destroyed );
#endif

			mlt_service_close( &self->parent );

			if ( destroy )
				free( self );
		}
	}
}
Ejemplo n.º 8
0
void mlt_service_cache_put( mlt_service self, const char *name, void* data, int size, mlt_destructor destructor )
{
	mlt_log( self, MLT_LOG_DEBUG, "%s: name %s object %p data %p\n", __FUNCTION__, name, self, data );
	mlt_cache cache = get_cache( self, name );

	if ( cache )
		mlt_cache_put( cache, self, data, size, destructor );
}
Ejemplo n.º 9
0
mlt_cache_item mlt_service_cache_get( mlt_service self, const char *name )
{
	mlt_log( self, MLT_LOG_DEBUG, "%s: name %s object %p\n", __FUNCTION__, name, self );
	mlt_cache_item result = NULL;
	mlt_cache cache = get_cache( self, name );

	if ( cache )
		result = mlt_cache_get( cache, self );

	return result;
}
Ejemplo n.º 10
0
Archivo: mlt_cache.c Proyecto: rayl/MLT
void mlt_cache_close( mlt_cache cache )
{
    if ( cache )
    {
        while ( cache->count-- )
        {
            void *object = cache->current[ cache->count ];
            mlt_log( NULL, MLT_LOG_DEBUG, "%s: %d = %p\n", __FUNCTION__, cache->count, object );
            cache_object_close( cache, object, NULL );
        }
        mlt_properties_close( cache->active );
        mlt_properties_close( cache->garbage );
        pthread_mutex_destroy( &cache->mutex );
        free( cache );
    }
}
Ejemplo n.º 11
0
mlt_frame mlt_cache_get_frame( mlt_cache cache, mlt_position position )
{
	mlt_frame result = NULL;
	pthread_mutex_lock( &cache->mutex );
	mlt_frame *hit = shuffle_get_frame( cache, position );
	mlt_frame *alt = (mlt_frame*) ( cache->current == cache->A ? cache->B : cache->A );

	if ( hit )
	{
		// copy the hit to the MRU end
		alt[ cache->count - 1 ] = *hit;
		hit = &alt[ cache->count - 1 ];

		result = mlt_frame_clone( *hit, 1 );
		mlt_log( NULL, MLT_LOG_DEBUG, "%s: get %d = %p\n", __FUNCTION__, cache->count - 1, *hit );

		// swap the current array
		cache->current = (void**) alt;
	}
	pthread_mutex_unlock( &cache->mutex );

	return result;
}
Ejemplo n.º 12
0
Archivo: vdpau.c Proyecto: aib/mlt
static int vdpau_init( producer_avformat self )
{
	if ( !vdpau_supported )
		return 0;
	mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_init\n" );
	int success = 0;
	mlt_properties properties = MLT_PRODUCER_PROPERTIES( self->parent );
	Display *display = XOpenDisplay( NULL );
	
	if ( !display || mlt_properties_get_int( properties, "novdpau" )
	     || ( getenv( "MLT_NO_VDPAU" ) && strcmp( getenv( "MLT_NO_VDPAU" ), "1" ) == 0 ) )
		return success;

	void *object = NULL;
	if ( !vdpau_init_done )
	{
		int flags = RTLD_NOW;
		object = dlopen( "/usr/lib/libvdpau.so", flags );
#ifdef ARCH_X86_64
		if ( !object )
			object = dlopen( "/usr/lib64/libvdpau.so", flags );
		if ( !object )
			object = dlopen( "/usr/lib/x86_64-linux-gnu/libvdpau.so.1", flags );
#elif ARCH_X86
		if ( !object )
			object = dlopen( "/usr/lib/i386-linux-gnu/libvdpau.so.1", flags );
#endif
		if ( !object )
			object = dlopen( "/usr/local/lib/libvdpau.so", flags );
		if ( object )
			vdpau_device_create_x11 = dlsym( object, "vdp_device_create_x11" );
		else
		{
			mlt_log( MLT_PRODUCER_SERVICE(self->parent), MLT_LOG_WARNING, "%s: failed to dlopen libvdpau.so\n  (%s)\n", __FUNCTION__, dlerror() );
			// Don't try again.
			vdpau_supported = 0;
			return success;
		}
	}
			
	if ( vdpau_device_create_x11 )
	{
		int screen = mlt_properties_get_int( properties, "x11_screen" );

		self->vdpau = calloc( 1, sizeof( *self->vdpau ) );
		self->vdpau->device = VDP_INVALID_HANDLE;
		self->vdpau->decoder = VDP_INVALID_HANDLE;
				
		mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "X11 Display = %p\n", display );
		if ( VDP_STATUS_OK == vdpau_device_create_x11( display, screen, &self->vdpau->device, &vdp_get_proc_address ) )
		{
			if ( !vdpau_init_done ) {
				vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_GET_ERROR_STRING, (void**) &vdp_get_error_string );
				vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_GET_API_VERSION, (void**) &vdp_get_api_version );
				vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_GET_INFORMATION_STRING, (void**) &vdp_get_information_string );
				vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_VIDEO_SURFACE_CREATE, (void**) &vdp_surface_create );
				vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_VIDEO_SURFACE_DESTROY, (void**) &vdp_surface_destroy );
				vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR, (void**) &vdp_surface_get_bits );
				vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_DECODER_CREATE, (void**) &vdp_decoder_create );
				vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_DECODER_DESTROY, (void**) &vdp_decoder_destroy );
				vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_DECODER_RENDER, (void**) &vdp_decoder_render );
				vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_DEVICE_DESTROY, (void**) &vdp_device_destroy );
				vdpau_init_done = 1;
			}
			success = 1;
		}
	}
	
	if ( !success )
	{
		mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "VDPAU failed to initialize device\n" );
		if ( object )
			dlclose( object );
		free( self->vdpau );
		self->vdpau = NULL;
	}

	return success;
}
Ejemplo n.º 13
0
int mlt_consumer_start( mlt_consumer self )
{
	if ( !mlt_consumer_is_stopped( self ) )
		return 0;

	// Stop listening to the property-changed event
	mlt_event_block( self->event_listener );

	// Get the properies
	mlt_properties properties = MLT_CONSUMER_PROPERTIES( self );

	// Determine if there's a test card producer
	char *test_card = mlt_properties_get( properties, "test_card" );

	// Just to make sure nothing is hanging around...
	pthread_mutex_lock( &self->put_mutex );
	self->put = NULL;
	self->put_active = 1;
	pthread_mutex_unlock( &self->put_mutex );

	// Deal with it now.
	if ( test_card != NULL )
	{
		if ( mlt_properties_get_data( properties, "test_card_producer", NULL ) == NULL )
		{
			// Create a test card producer
			mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) );
			mlt_producer producer = mlt_factory_producer( profile, NULL, test_card );

			// Do we have a producer
			if ( producer != NULL )
			{
				// Test card should loop I guess...
				mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer ), "eof", "loop" );
				//mlt_producer_set_speed( producer, 0 );
				//mlt_producer_set_in_and_out( producer, 0, 0 );

				// Set the test card on the consumer
				mlt_properties_set_data( properties, "test_card_producer", producer, 0, ( mlt_destructor )mlt_producer_close, NULL );
			}
		}
	}
	else
	{
		// Allow the hash table to speed things up
		mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL );
	}

	// The profile could have changed between a stop and a restart.
	apply_profile_properties( self, mlt_service_profile( MLT_CONSUMER_SERVICE(self) ), properties );

	// Set the frame duration in microseconds for the frame-dropping heuristic
	int frame_rate_num = mlt_properties_get_int( properties, "frame_rate_num" );
	int frame_rate_den = mlt_properties_get_int( properties, "frame_rate_den" );
	int frame_duration = 0;

	if ( frame_rate_num && frame_rate_den )
	{
		frame_duration = 1000000 / frame_rate_num * frame_rate_den;
	}

	mlt_properties_set_int( properties, "frame_duration", frame_duration );

	// Check and run an ante command
	if ( mlt_properties_get( properties, "ante" ) )
		if ( system( mlt_properties_get( properties, "ante" ) ) == -1 )
			mlt_log( MLT_CONSUMER_SERVICE( self ), MLT_LOG_ERROR, "system(%s) failed!\n", mlt_properties_get( properties, "ante" ) );

	// Set the real_time preference
	self->real_time = mlt_properties_get_int( properties, "real_time" );

	// For worker threads implementation, buffer must be at least # threads
	if ( abs( self->real_time ) > 1 && mlt_properties_get_int( properties, "buffer" ) <= abs( self->real_time ) )
		mlt_properties_set_int( properties, "_buffer", abs( self->real_time ) + 1 );

	// Get the image format to use for rendering threads
	const char* format = mlt_properties_get( properties, "mlt_image_format" );
	if ( format )
	{
		if ( !strcmp( format, "rgb24" ) )
			self->format = mlt_image_rgb24;
		else if ( !strcmp( format, "rgb24a" ) )
			self->format = mlt_image_rgb24a;
		else if ( !strcmp( format, "yuv420p" ) )
			self->format = mlt_image_yuv420p;
		else if ( !strcmp( format, "none" ) )
			self->format = mlt_image_none;
		else
			self->format = mlt_image_yuv422;
	}

	// Start the service
	if ( self->start != NULL )
		return self->start( self );

	return 0;
}
Ejemplo n.º 14
0
static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int track )
{
	mlt_tractor self = parent->child;

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

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

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

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

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

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

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

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

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

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

			// Temporary properties
			mlt_properties temp_properties = NULL;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		// Prepare the next frame
		mlt_producer_prepare_next( parent );

		// Indicate our found status
		return 0;
	}
	else
	{
		// Generate a test card
		*frame = mlt_frame_init( MLT_PRODUCER_SERVICE( parent ) );
		return 0;
	}
}
Ejemplo n.º 15
0
Archivo: mlt_cache.c Proyecto: rayl/MLT
void mlt_cache_put( mlt_cache cache, void *object, void* data, int size, mlt_destructor destructor )
{
    pthread_mutex_lock( &cache->mutex );
    void **hit = shuffle_get_hit( cache, object );
    void **alt = cache->current == cache->A ? cache->B : cache->A;

    // add the object to the cache
    if ( hit )
    {
        // release the old data
        pthread_mutex_unlock( &cache->mutex );
        cache_object_close( cache, *hit, NULL );
        pthread_mutex_lock( &cache->mutex );
        // 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
        pthread_mutex_unlock( &cache->mutex );
        cache_object_close( cache, cache->current[0], NULL );
        pthread_mutex_lock( &cache->mutex );

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

    // Fetch the cache item
    char key[19];
    sprintf( key, "%p", object );
    mlt_cache_item item = mlt_properties_get_data( cache->active, key, NULL );
    if ( !item )
    {
        item = calloc( 1, sizeof( mlt_cache_item_s ) );
        if ( item )
            mlt_properties_set_data( cache->active, key, item, 0, free, NULL );
    }
    if ( item )
    {
        // If updating the cache item but not all references are released
        // copy the item to the garbage collection.
        if ( item->refcount > 0 && item->data )
        {
            mlt_cache_item orphan = calloc( 1, sizeof( mlt_cache_item_s ) );
            if ( orphan )
            {
                mlt_log( NULL, MLT_LOG_DEBUG, "adding to garbage collection object %p data %p\n", item->object, item->data );
                *orphan = *item;
                sprintf( key, "%p", orphan->data );
                // We store in the garbage collection by data address, not the owner's!
                mlt_properties_set_data( cache->garbage, key, orphan, 0, free, NULL );
            }
        }

        // Set/update the cache item
        item->cache = cache;
        item->object = object;
        item->data = data;
        item->size = size;
        item->destructor = destructor;
        item->refcount = 1;
    }

    // swap the current array
    cache->current = alt;
    pthread_mutex_unlock( &cache->mutex );
}
Ejemplo n.º 16
0
bool ServiceManager::initialize(int width, int height)
{
    if (effects)
        return true;

    mlt_properties properties = MLT_SERVICE_PROPERTIES(service);

    // Create and initialize Effects
    const char* fileName = mlt_properties_get(properties, "resource");
    if (!fileName) {
        mlt_log(service, MLT_LOG_ERROR, "No 'resource' property found\n");
        return false;
    }
    bool isTransparent = mlt_properties_get_int(properties, "transparent") || mlt_service_identify(service) == filter_type;
    parameters = new ServiceParameters(service);
    effects = WebVfx::createEffects(fileName, width, height,
                                    parameters, isTransparent);
    if (!effects) {
        mlt_log(service, MLT_LOG_ERROR,
                "Failed to create WebVfx Effects for resource %s\n", fileName);
        return false;
    }

    // Iterate over image map - save source and target image names,
    // and create an ImageProducer for each extra image.
    char* factory = mlt_properties_get(properties, "factory");
    WebVfx::Effects::ImageTypeMapIterator it(effects->getImageTypeMap());
    while (it.hasNext()) {
        it.next();

        const QString& imageName = it.key();

        switch (it.value()) {

        case WebVfx::Effects::SourceImageType:
            sourceImageName = imageName;
            break;

        case WebVfx::Effects::TargetImageType:
            targetImageName = imageName;
            break;

        case WebVfx::Effects::ExtraImageType:
        {
            if (!imageProducers)
                imageProducers = new std::vector<ImageProducer*>(3);

            // Property prefix "producer.<name>."
            QString producerPrefix("producer.");
            producerPrefix.append(imageName).append(".");

            // Find producer.<name>.resource property
            QString resourceName(producerPrefix);
            resourceName.append("resource");
            char* resource = mlt_properties_get(properties, resourceName.toLatin1().constData());
            if (resource) {
                mlt_producer producer = mlt_factory_producer(mlt_service_profile(service), factory, resource);
                if (!producer) {
                    mlt_log(service, MLT_LOG_ERROR, "WebVfx failed to create extra image producer for %s\n", resourceName.toLatin1().constData());
                    return false;
                }
                // Copy producer.<name>.* properties onto producer
                mlt_properties_pass(MLT_PRODUCER_PROPERTIES(producer), properties, producerPrefix.toLatin1().constData());
                // Append ImageProducer to vector
                imageProducers->insert(imageProducers->end(), new ImageProducer(imageName, producer));
            }
            else
                mlt_log(service, MLT_LOG_WARNING, "WebVfx no producer resource property specified for extra image %s\n", resourceName.toLatin1().constData());
            break;
        }

        default:
            mlt_log(service, MLT_LOG_ERROR, "Invalid WebVfx image type %d\n", it.value());
            break;
        }
    }

    return true;
}
Ejemplo n.º 17
0
static int producer_get_frame( mlt_service service, mlt_frame_ptr frame, int index )
{
	int result = 1;
	mlt_producer self = service != NULL ? service->child : NULL;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	return result;
}
Ejemplo n.º 18
0
static int transition_get_frame( mlt_service service, mlt_frame_ptr frame, int index )
{
	int error = 0;
	mlt_transition self = service->child;

	mlt_properties properties = MLT_TRANSITION_PROPERTIES( self );

	int accepts_blanks = mlt_properties_get_int( properties, "accepts_blanks" );
	int a_track = mlt_properties_get_int( properties, "a_track" );
	int b_track = mlt_properties_get_int( properties, "b_track" );
	mlt_position in = mlt_properties_get_position( properties, "in" );
	mlt_position out = mlt_properties_get_position( properties, "out" );
	int always_active = mlt_properties_get_int( properties, "always_active" );
	int type = mlt_properties_get_int( properties, "_transition_type" );
	int reverse_order = 0;

	// Ensure that we have the correct order
	if ( a_track > b_track )
	{
		reverse_order = 1;
		a_track = b_track;
		b_track = mlt_properties_get_int( properties, "a_track" );
	}

	// Only act on this operation once per multitrack iteration from the tractor
	if ( !self->held )
	{
		int active = 0;
		int i = 0;
		int a_frame = a_track;
		int b_frame = b_track;
		mlt_position position;
		int ( *invalid )( mlt_frame ) = type == 1 ? mlt_frame_is_test_card : mlt_frame_is_test_audio;

		// Initialise temporary store
		if ( self->frames == NULL )
			self->frames = calloc( b_track + 1, sizeof( mlt_frame ) );

		// Get all frames between a and b
		for( i = a_track; i <= b_track; i ++ )
			mlt_service_get_frame( self->producer, &self->frames[ i ], i );

		// We're holding these frames until the last_track frame property is received
		self->held = 1;

		// When we need to locate the a_frame
		switch( type )
		{
			case 1:
			case 2:
				// Some transitions (esp. audio) may accept blank frames
				active = accepts_blanks;

				// If we're not active then...
				if ( !active )
				{
					// Hunt for the a_frame
					while( a_frame <= b_frame && invalid( self->frames[ a_frame ] ) )
						a_frame ++;

					// Determine if we're active now
					active = a_frame != b_frame && !invalid( self->frames[ b_frame ] );
				}
				break;

			default:
				mlt_log( service, MLT_LOG_ERROR, "invalid transition type\n" );
				break;
		}

		// Now handle the non-always active case
		if ( active && !always_active && a_frame <= b_track )
		{
			// For non-always-active transitions, we need the current position of the a frame
			position = mlt_frame_get_position( self->frames[ a_frame ] );

			// If a is in range, we're active
			active = position >= in && ( out == 0 || position <= out );
		}

		// Finally, process the a and b frames
		if ( active && !mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( self ), "disable" ) )
		{
			int frame_nb = ( !reverse_order && a_frame <= b_track )? a_frame : b_frame;
			mlt_frame a_frame_ptr = self->frames[ frame_nb ];
			frame_nb = ( !reverse_order || a_frame > b_track )? b_frame : a_frame;
			mlt_frame b_frame_ptr = self->frames[ frame_nb ];
			int a_hide = mlt_properties_get_int( MLT_FRAME_PROPERTIES( a_frame_ptr ), "hide" );
			int b_hide = mlt_properties_get_int( MLT_FRAME_PROPERTIES( b_frame_ptr ), "hide" );
			if ( !( a_hide & type ) && !( b_hide & type ) )
			{
				// Add hooks for pre-processing frames
				mlt_frame_push_service( a_frame_ptr, self );
				mlt_frame_push_get_image( a_frame_ptr, get_image_a );
				mlt_frame_push_frame( b_frame_ptr, a_frame_ptr );
				mlt_frame_push_service( b_frame_ptr, self );
				mlt_frame_push_get_image( b_frame_ptr, get_image_b );

				// Process the transition
				*frame = mlt_transition_process( self, a_frame_ptr, b_frame_ptr );

				// We need to ensure that the tractor doesn't consider this frame for output
				if ( *frame == a_frame_ptr )
					b_hide |= type;
				else
					a_hide |= type;

				mlt_properties_set_int( MLT_FRAME_PROPERTIES( a_frame_ptr ), "hide", a_hide );
				mlt_properties_set_int( MLT_FRAME_PROPERTIES( b_frame_ptr ), "hide", b_hide );
			}
		}
	}

	// Obtain the frame from the cache or the producer we're attached to
	if ( index >= a_track && index <= b_track )
		*frame = self->frames[ index ];
	else
		error = mlt_service_get_frame( self->producer, frame, index );

	// Determine if that was the last track
	self->held = !mlt_properties_get_int( MLT_FRAME_PROPERTIES( *frame ), "last_track" );

	return error;
}