mlt_consumer consumer_multi_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_consumer consumer = mlt_consumer_new( profile ); if ( consumer ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES(consumer); // Set defaults mlt_properties_set( properties, "resource", arg ); mlt_properties_set_int( properties, "real_time", -1 ); mlt_properties_set_int( properties, "terminate_on_pause", 1 ); // Init state mlt_properties_set_int( properties, "joined", 1 ); // Assign callbacks consumer->close = consumer_close; consumer->start = start; consumer->stop = stop; consumer->is_stopped = is_stopped; } return consumer; }
mlt_consumer consumer_null_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Allocate the consumer mlt_consumer this = mlt_consumer_new( profile ); // If memory allocated and initialises without error if ( this != NULL ) { // Assign close callback this->close = consumer_close; // Set up start/stop/terminated callbacks this->start = consumer_start; this->stop = consumer_stop; this->is_stopped = consumer_is_stopped; } // Return this return this; }
mlt_consumer consumer_blipflash_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Allocate the consumer mlt_consumer consumer = mlt_consumer_new( profile ); mlt_properties consumer_properties = MLT_CONSUMER_PROPERTIES( consumer ); avsync_stats* stats = NULL; // If memory allocated and initializes without error if ( consumer != NULL ) { // Set up start/stop/terminated callbacks consumer->close = consumer_close; consumer->start = consumer_start; consumer->stop = consumer_stop; consumer->is_stopped = consumer_is_stopped; stats = mlt_pool_alloc( sizeof( avsync_stats ) ); stats->flash_history_count = 0; stats->blip_history_count = 0; stats->blip_in_progress = 0; stats->samples_since_blip = 0; stats->blip = 0; stats->flash = 0; stats->sample_offset = INT_MAX; stats->report_frames = 0; stats->out_file = stdout; if ( arg != NULL ) { FILE* out_file = fopen( arg, "w" ); if ( out_file != NULL ) stats->out_file = out_file; } mlt_properties_set_data( consumer_properties, "_stats", stats, 0, NULL, NULL ); mlt_properties_set( consumer_properties, "report", "blip" ); } // Return this return consumer; }
static int get_frame( mlt_producer self, mlt_frame_ptr frame, int index ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES(self); context cx = mlt_properties_get_data( properties, "context", NULL ); if ( !cx ) { // Allocate and initialize our context cx = mlt_pool_alloc( sizeof( struct context_s ) ); memset( cx, 0, sizeof( *cx ) ); mlt_properties_set_data( properties, "context", cx, 0, mlt_pool_release, NULL ); cx->self = self; char *profile_name = mlt_properties_get( properties, "profile" ); if ( !profile_name ) profile_name = mlt_properties_get( properties, "mlt_profile" ); mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( self ) ); if ( profile_name ) { cx->profile = mlt_profile_init( profile_name ); cx->profile->is_explicit = 1; } else { cx->profile = mlt_profile_clone( profile ); cx->profile->is_explicit = 0; } // Encapsulate a real producer for the resource cx->producer = mlt_factory_producer( cx->profile, NULL, mlt_properties_get( properties, "resource" ) ); if ( ( profile_name && !strcmp( profile_name, "auto" ) ) || mlt_properties_get_int( properties, "autoprofile" ) ) { mlt_profile_from_producer( cx->profile, cx->producer ); mlt_producer_close( cx->producer ); cx->producer = mlt_factory_producer( cx->profile, NULL, mlt_properties_get( properties, "resource" ) ); } // Since we control the seeking, prevent it from seeking on its own mlt_producer_set_speed( cx->producer, 0 ); cx->audio_position = -1; // We will encapsulate a consumer cx->consumer = mlt_consumer_new( cx->profile ); // Do not use _pass_list on real_time so that it defaults to 0 in the absence of // an explicit real_time property. mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( cx->consumer ), "real_time", mlt_properties_get_int( properties, "real_time" ) ); mlt_properties_pass_list( MLT_CONSUMER_PROPERTIES( cx->consumer ), properties, "buffer, prefill, deinterlace_method, rescale" ); // Connect it all together mlt_consumer_connect( cx->consumer, MLT_PRODUCER_SERVICE( cx->producer ) ); mlt_consumer_start( cx->consumer ); } // Generate a frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( self ) ); if ( *frame ) { // Seek the producer to the correct place // Calculate our positions double actual_position = (double) mlt_producer_frame( self ); if ( mlt_producer_get_speed( self ) != 0 ) actual_position *= mlt_producer_get_speed( self ); mlt_position need_first = floor( actual_position ); mlt_producer_seek( cx->producer, lrint( need_first * mlt_profile_fps( cx->profile ) / mlt_producer_get_fps( self ) ) ); // Get the nested frame mlt_frame nested_frame = mlt_consumer_rt_frame( cx->consumer ); // Stack the producer and our methods on the nested frame mlt_frame_push_service( *frame, nested_frame ); mlt_frame_push_service( *frame, cx ); mlt_frame_push_get_image( *frame, get_image ); mlt_frame_push_audio( *frame, nested_frame ); mlt_frame_push_audio( *frame, cx ); mlt_frame_push_audio( *frame, get_audio ); // Give the returned frame temporal identity mlt_frame_set_position( *frame, mlt_producer_position( self ) ); // Store the nested frame on the produced frame for destruction mlt_properties frame_props = MLT_FRAME_PROPERTIES( *frame ); mlt_properties_set_data( frame_props, "_producer_consumer.frame", nested_frame, 0, (mlt_destructor) mlt_frame_close, NULL ); // Inform the normalizers about our video properties mlt_properties_set_double( frame_props, "aspect_ratio", mlt_profile_sar( cx->profile ) ); mlt_properties_set_int( frame_props, "width", cx->profile->width ); mlt_properties_set_int( frame_props, "height", cx->profile->height ); mlt_properties_set_int( frame_props, "meta.media.width", cx->profile->width ); mlt_properties_set_int( frame_props, "meta.media.height", cx->profile->height ); mlt_properties_set_int( frame_props, "progressive", cx->profile->progressive ); } // Calculate the next timecode mlt_producer_prepare_next( self ); return 0; }