mlt_tractor mlt_tractor_new( ) { mlt_tractor self = calloc( 1, sizeof( struct mlt_tractor_s ) ); if ( self != NULL ) { mlt_producer producer = &self->parent; if ( mlt_producer_init( producer, self ) == 0 ) { mlt_multitrack multitrack = mlt_multitrack_init( ); mlt_field field = mlt_field_new( multitrack, self ); mlt_properties props = MLT_PRODUCER_PROPERTIES( producer ); mlt_properties_set( props, "resource", "<tractor>" ); mlt_properties_set( props, "mlt_type", "mlt_producer" ); mlt_properties_set( props, "mlt_service", "tractor" ); mlt_properties_set_position( props, "in", 0 ); mlt_properties_set_position( props, "out", 0 ); mlt_properties_set_position( props, "length", 0 ); mlt_properties_set_data( props, "multitrack", multitrack, 0, ( mlt_destructor )mlt_multitrack_close, NULL ); mlt_properties_set_data( props, "field", field, 0, ( mlt_destructor )mlt_field_close, NULL ); mlt_events_listen( MLT_MULTITRACK_PROPERTIES( multitrack ), self, "producer-changed", ( mlt_listener )mlt_tractor_listener ); producer->get_frame = producer_get_frame; producer->close = ( mlt_destructor )mlt_tractor_close; producer->close_object = self; } else { free( self ); self = NULL; } } return self; }
int mlt_producer_seek( mlt_producer self, mlt_position position ) { // Determine eof handling mlt_properties properties = MLT_PRODUCER_PROPERTIES( self ); char *eof = mlt_properties_get( properties, "eof" ); int use_points = 1 - mlt_properties_get_int( properties, "ignore_points" ); // Recursive behaviour for cuts - repositions parent and then repositions cut // hence no return on this condition if ( mlt_producer_is_cut( self ) ) mlt_producer_seek( mlt_producer_cut_parent( self ), position + mlt_producer_get_in( self ) ); // Check bounds if ( position < 0 || mlt_producer_get_playtime( self ) == 0 ) { position = 0; } else if ( use_points && ( eof == NULL || !strcmp( eof, "pause" ) ) && position >= mlt_producer_get_playtime( self ) ) { mlt_producer_set_speed( self, 0 ); position = mlt_producer_get_playtime( self ) - 1; } else if ( use_points && eof && !strcmp( eof, "loop" ) && position >= mlt_producer_get_playtime( self ) ) { position = (int)position % (int)mlt_producer_get_playtime( self ); } // Set the position mlt_properties_set_position( MLT_PRODUCER_PROPERTIES( self ), "_position", position ); // Calculate the absolute frame mlt_properties_set_position( MLT_PRODUCER_PROPERTIES( self ), "_frame", use_points * mlt_producer_get_in( self ) + position ); return 0; }
int mlt_producer_set_in_and_out( mlt_producer self, mlt_position in, mlt_position out ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES( self ); // Correct ins and outs if necessary if ( in < 0 ) in = 0; else if ( in >= mlt_producer_get_length( self ) ) in = mlt_producer_get_length( self ) - 1; if ( ( out < 0 || out >= mlt_producer_get_length( self ) ) && !mlt_producer_is_blank( self ) ) out = mlt_producer_get_length( self ) - 1; else if ( ( out < 0 || out >= mlt_producer_get_length( self ) ) && mlt_producer_is_blank( self ) ) mlt_properties_set_position( MLT_PRODUCER_PROPERTIES( self ), "length", out + 1 ); else if ( out < 0 ) out = 0; // Swap ins and outs if wrong if ( out < in ) { mlt_position t = in; in = out; out = t; } // Set the values mlt_events_block( properties, properties ); mlt_properties_set_position( properties, "in", in ); mlt_events_unblock( properties, properties ); mlt_properties_set_position( properties, "out", out ); return 0; }
int mlt_filter_init( mlt_filter self, void *child ) { mlt_service service = &self->parent; memset( self, 0, sizeof( struct mlt_filter_s ) ); self->child = child; if ( mlt_service_init( service, self ) == 0 ) { mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); // Override the get_frame method service->get_frame = filter_get_frame; // Define the destructor service->close = ( mlt_destructor )mlt_filter_close; service->close_object = self; // Default in, out, track properties mlt_properties_set_position( properties, "in", 0 ); mlt_properties_set_position( properties, "out", 0 ); mlt_properties_set_int( properties, "track", 0 ); return 0; } return 1; }
int mlt_frame_set_position( mlt_frame self, mlt_position value ) { // Only set the original_position the first time. if ( ! mlt_properties_get( MLT_FRAME_PROPERTIES( self ), "original_position" ) ) mlt_properties_set_position( MLT_FRAME_PROPERTIES( self ), "original_position", value ); return mlt_properties_set_position( MLT_FRAME_PROPERTIES( self ), "_position", value ); }
void mlt_service_apply_filters( mlt_service self, mlt_frame frame, int index ) { int i; mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); mlt_properties service_properties = MLT_SERVICE_PROPERTIES( self ); mlt_service_base *base = self->local; mlt_position position = mlt_frame_get_position( frame ); mlt_position self_in = mlt_properties_get_position( service_properties, "in" ); mlt_position self_out = mlt_properties_get_position( service_properties, "out" ); if ( index == 0 || mlt_properties_get_int( service_properties, "_filter_private" ) == 0 ) { // Process the frame with the attached filters for ( i = 0; i < base->filter_count; i ++ ) { if ( base->filters[ i ] != NULL ) { mlt_position in = mlt_filter_get_in( base->filters[ i ] ); mlt_position out = mlt_filter_get_out( base->filters[ i ] ); int disable = mlt_properties_get_int( MLT_FILTER_PROPERTIES( base->filters[ i ] ), "disable" ); if ( !disable && ( ( in == 0 && out == 0 ) || ( position >= in && ( position <= out || out == 0 ) ) ) ) { mlt_properties_set_position( frame_properties, "in", in == 0 ? self_in : in ); mlt_properties_set_position( frame_properties, "out", out == 0 ? self_out : out ); mlt_filter_process( base->filters[ i ], frame ); mlt_service_apply_filters( MLT_FILTER_SERVICE( base->filters[ i ] ), frame, index + 1 ); } } } } }
int mlt_producer_init( mlt_producer self, void *child ) { // Check that we haven't received NULL int error = self == NULL; // Continue if no error if ( error == 0 ) { #ifdef _MLT_PRODUCER_CHECKS_ producers_created ++; #endif // Initialise the producer memset( self, 0, sizeof( struct mlt_producer_s ) ); // Associate with the child self->child = child; // Initialise the service if ( mlt_service_init( &self->parent, self ) == 0 ) { // The parent is the service mlt_service parent = &self->parent; // Define the parent close parent->close = ( mlt_destructor )mlt_producer_close; parent->close_object = self; // For convenience, we'll assume the close_object is self self->close_object = self; // Get the properties of the parent mlt_properties properties = MLT_SERVICE_PROPERTIES( parent ); // Set the default properties mlt_properties_set( properties, "mlt_type", "mlt_producer" ); mlt_properties_set_position( properties, "_position", 0.0 ); mlt_properties_set_double( properties, "_frame", 0 ); mlt_properties_set_double( properties, "_speed", 1.0 ); mlt_properties_set_position( properties, "in", 0 ); char *e = getenv( "MLT_DEFAULT_PRODUCER_LENGTH" ); int p = e ? atoi( e ) : 15000; mlt_properties_set_position( properties, "out", p - 1 ); mlt_properties_set_position( properties, "length", p ); mlt_properties_set( properties, "eof", "pause" ); mlt_properties_set( properties, "resource", "<producer>" ); // Override service get_frame parent->get_frame = producer_get_frame; mlt_events_listen( properties, self, "service-changed", ( mlt_listener )mlt_producer_service_changed ); mlt_events_listen( properties, self, "property-changed", ( mlt_listener )mlt_producer_property_changed ); mlt_events_register( properties, "producer-changed", NULL ); } } return error; }
int mlt_producer_clear( mlt_producer self ) { if ( self != NULL ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES( self ); mlt_events_block( properties, properties ); mlt_properties_set_position( properties, "in", 0 ); mlt_events_unblock( properties, properties ); mlt_properties_set_position( properties, "out", -1 ); } return 0; }
void mlt_tractor_refresh( mlt_tractor self ) { mlt_multitrack multitrack = mlt_tractor_multitrack( self ); mlt_properties multitrack_props = MLT_MULTITRACK_PROPERTIES( multitrack ); mlt_properties properties = MLT_TRACTOR_PROPERTIES( self ); mlt_events_block( multitrack_props, properties ); mlt_events_block( properties, properties ); mlt_multitrack_refresh( multitrack ); mlt_properties_set_position( properties, "in", 0 ); mlt_properties_set_position( properties, "out", mlt_properties_get_position( multitrack_props, "out" ) ); mlt_events_unblock( properties, properties ); mlt_events_unblock( multitrack_props, properties ); mlt_properties_set_position( properties, "length", mlt_properties_get_position( multitrack_props, "length" ) ); }
int mlt_filter_connect( mlt_filter self, mlt_service producer, int index ) { int ret = mlt_service_connect_producer( &self->parent, producer, index ); // If the connection was successful, grab the producer, track and reset in/out if ( ret == 0 ) { mlt_properties properties = MLT_SERVICE_PROPERTIES( &self->parent ); mlt_properties_set_position( properties, "in", 0 ); mlt_properties_set_position( properties, "out", 0 ); mlt_properties_set_int( properties, "track", index ); } return ret; }
static int jackrack_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the filter service mlt_filter filter = mlt_frame_pop_audio( frame ); // Get the filter properties mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); int jack_frequency = mlt_properties_get_int( filter_properties, "_sample_rate" ); // Get the producer's audio *format = mlt_audio_float; mlt_frame_get_audio( frame, buffer, format, &jack_frequency, channels, samples ); // TODO: Deal with sample rate differences if ( *frequency != jack_frequency ) mlt_log_error( MLT_FILTER_SERVICE( filter ), "mismatching frequencies JACK = %d actual = %d\n", jack_frequency, *frequency ); *frequency = jack_frequency; // Initialise Jack ports and connections if needed if ( mlt_properties_get_int( filter_properties, "_samples" ) == 0 ) mlt_properties_set_int( filter_properties, "_samples", *samples ); // Get the filter-specific properties jack_ringbuffer_t **output_buffers = mlt_properties_get_data( filter_properties, "output_buffers", NULL ); jack_ringbuffer_t **input_buffers = mlt_properties_get_data( filter_properties, "input_buffers", NULL ); // pthread_mutex_t *output_lock = mlt_properties_get_data( filter_properties, "output_lock", NULL ); // pthread_cond_t *output_ready = mlt_properties_get_data( filter_properties, "output_ready", NULL ); // Process the audio float *q = (float*) *buffer; size_t size = *samples * sizeof(float); int j; // struct timespec tm = { 0, 0 }; // Write into output ringbuffer for ( j = 0; j < *channels; j++ ) { if ( jack_ringbuffer_write_space( output_buffers[j] ) >= size ) jack_ringbuffer_write( output_buffers[j], (char*)( q + j * *samples ), size ); } // Synchronization phase - wait for signal from Jack process while ( jack_ringbuffer_read_space( input_buffers[ *channels - 1 ] ) < size ) ; //pthread_cond_wait( output_ready, output_lock ); // Read from input ringbuffer for ( j = 0; j < *channels; j++, q++ ) { if ( jack_ringbuffer_read_space( input_buffers[j] ) >= size ) jack_ringbuffer_read( input_buffers[j], (char*)( q + j * *samples ), size ); } // help jack_sync() indicate when we are rolling mlt_position pos = mlt_frame_get_position( frame ); mlt_properties_set_position( filter_properties, "_last_pos", pos ); return 0; }
mlt_producer mlt_producer_cut( mlt_producer self, int in, int out ) { mlt_producer result = mlt_producer_new( mlt_service_profile( MLT_PRODUCER_SERVICE( self ) ) ); mlt_producer parent = mlt_producer_cut_parent( self ); mlt_properties properties = MLT_PRODUCER_PROPERTIES( result ); mlt_properties parent_props = MLT_PRODUCER_PROPERTIES( parent ); mlt_properties_set_lcnumeric( properties, mlt_properties_get_lcnumeric( MLT_PRODUCER_PROPERTIES( self ) ) ); mlt_events_block( MLT_PRODUCER_PROPERTIES( result ), MLT_PRODUCER_PROPERTIES( result ) ); // Special case - allow for a cut of the entire producer (this will squeeze all other cuts to 0) if ( in <= 0 ) in = 0; if ( ( out < 0 || out >= mlt_producer_get_length( parent ) ) && !mlt_producer_is_blank( self ) ) out = mlt_producer_get_length( parent ) - 1; mlt_properties_inc_ref( parent_props ); mlt_properties_set_int( properties, "_cut", 1 ); mlt_properties_set_data( properties, "_cut_parent", parent, 0, ( mlt_destructor )mlt_producer_close, NULL ); mlt_properties_set_position( properties, "length", mlt_properties_get_position( parent_props, "length" ) ); mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( parent_props, "aspect_ratio" ) ); mlt_producer_set_in_and_out( result, in, out ); return result; }
static int getFrame(mlt_producer producer, mlt_frame_ptr frame, int /*index*/) { // Generate a frame *frame = mlt_frame_init(MLT_PRODUCER_SERVICE(producer)); if (*frame) { // Obtain properties of frame and producer mlt_properties properties = MLT_FRAME_PROPERTIES(*frame); // Set the producer on the frame properties mlt_properties_set_data(properties, kWebVfxProducerPropertyName, producer, 0, NULL, NULL); // Update timecode on the frame we're creating mlt_position position = mlt_producer_position(producer); mlt_frame_set_position(*frame, position); mlt_properties_set_position(properties, kWebVfxPositionPropertyName, position); // Set producer-specific frame properties mlt_properties_set_int(properties, "progressive", 1); // Push the get_image method mlt_frame_push_get_image(*frame, producerGetImage); } // Calculate the next timecode mlt_producer_prepare_next(producer); return 0; }
mlt_frame mlt_frame_init( mlt_service service ) { // Allocate a frame mlt_frame this = calloc( sizeof( struct mlt_frame_s ), 1 ); if ( this != NULL ) { mlt_profile profile = mlt_service_profile( service ); // Initialise the properties mlt_properties properties = &this->parent; mlt_properties_init( properties, this ); // Set default properties on the frame mlt_properties_set_position( properties, "_position", 0.0 ); mlt_properties_set_data( properties, "image", NULL, 0, NULL, NULL ); mlt_properties_set_int( properties, "width", profile? profile->width : 720 ); mlt_properties_set_int( properties, "height", profile? profile->height : 576 ); mlt_properties_set_int( properties, "normalised_width", profile? profile->width : 720 ); mlt_properties_set_int( properties, "normalised_height", profile? profile->height : 576 ); mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( NULL ) ); mlt_properties_set_data( properties, "audio", NULL, 0, NULL, NULL ); mlt_properties_set_data( properties, "alpha", NULL, 0, NULL, NULL ); // Construct stacks for frames and methods this->stack_image = mlt_deque_init( ); this->stack_audio = mlt_deque_init( ); this->stack_service = mlt_deque_init( ); } return this; }
mlt_frame mlt_filter_process( mlt_filter self, mlt_frame frame ) { mlt_properties properties = MLT_FILTER_PROPERTIES( self ); int disable = mlt_properties_get_int( properties, "disable" ); const char *unique_id = mlt_properties_get( properties, "_unique_id" ); mlt_position position = mlt_frame_get_position( frame ); char name[30]; // Make the properties key from unique id snprintf( name, sizeof(name), "pos.%s", unique_id ); name[sizeof(name) -1] = '\0'; // Save the position on the frame mlt_properties_set_position( MLT_FRAME_PROPERTIES( frame ), name, position ); if ( disable || self->process == NULL ) { return frame; } else { // Add a reference to this filter on the frame mlt_properties_inc_ref( MLT_FILTER_PROPERTIES(self) ); snprintf( name, sizeof(name), "filter.%s", unique_id ); name[sizeof(name) -1] = '\0'; mlt_properties_set_data( MLT_FRAME_PROPERTIES(frame), name, self, 0, (mlt_destructor) mlt_filter_close, NULL ); return self->process( self, frame ); } }
mlt_frame transition_process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame ) { char *name = mlt_properties_get( MLT_TRANSITION_PROPERTIES( transition ), "_unique_id" ); mlt_properties_set_position( MLT_FRAME_PROPERTIES( a_frame ), name, mlt_frame_get_position( a_frame ) ); mlt_frame_push_service( a_frame, transition ); mlt_frame_push_frame( a_frame, b_frame ); mlt_frame_push_get_image( a_frame, transition_get_image ); return a_frame; }
mlt_producer create_tracks( int argc, char **argv ) { // Create the field mlt_field field = mlt_field_init( ); // Obtain the multitrack mlt_multitrack multitrack = mlt_field_multitrack( field ); // Obtain the tractor mlt_tractor tractor = mlt_field_tractor( field ); // Obtain a composite transition mlt_transition transition = mlt_factory_transition( "composite", "10%,10%:15%x15%" ); // Create track 0 mlt_producer track0 = create_playlist( argc, argv ); // Get the length of track0 mlt_position length = mlt_producer_get_playtime( track0 ); // Create the watermark track mlt_producer track1 = mlt_factory_producer( NULL, "pango:" ); // Get the properties of track1 mlt_properties properties = mlt_producer_properties( track1 ); // Set the properties mlt_properties_set( properties, "text", "Hello\nWorld" ); mlt_properties_set_position( properties, "in", 0 ); mlt_properties_set_position( properties, "out", length - 1 ); mlt_properties_set_position( properties, "length", length ); // Now set the properties on the transition properties = mlt_transition_properties( transition ); mlt_properties_set_position( properties, "in", 0 ); mlt_properties_set_position( properties, "out", length - 1 ); // Add our tracks to the multitrack mlt_multitrack_connect( multitrack, track0, 0 ); mlt_multitrack_connect( multitrack, track1, 1 ); // Now plant the transition mlt_field_plant_transition( field, transition, 0, 1 ); // Now set the properties on the transition properties = mlt_tractor_properties( tractor ); // Ensure clean up and set properties correctly mlt_properties_set_data( properties, "multitrack", multitrack, 0, ( mlt_destructor )mlt_multitrack_close, NULL ); mlt_properties_set_data( properties, "field", field, 0, ( mlt_destructor )mlt_field_close, NULL ); mlt_properties_set_data( properties, "track0", track0, 0, ( mlt_destructor )mlt_producer_close, NULL ); mlt_properties_set_data( properties, "track1", track1, 0, ( mlt_destructor )mlt_producer_close, NULL ); mlt_properties_set_data( properties, "transition", transition, 0, ( mlt_destructor )mlt_transition_close, NULL ); mlt_properties_set_position( properties, "length", length ); mlt_properties_set_position( properties, "out", length - 1 ); // Return the tractor return mlt_tractor_producer( tractor ); }
mlt_producer producer_kino_init( mlt_profile profile, mlt_service_type type, const char *id, char *filename ) { kino_wrapper wrapper = kino_wrapper_init( ); if ( kino_wrapper_open( wrapper, filename ) ) { producer_kino this = calloc( 1, sizeof( struct producer_kino_s ) ); if ( this != NULL && mlt_producer_init( &this->parent, this ) == 0 ) { mlt_producer producer = &this->parent; mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); double fps = kino_wrapper_is_pal( wrapper ) ? 25 : 30000.0 / 1001.0; // Assign the wrapper this->wrapper = wrapper; // Pass wrapper properties (frame rate, count etc) mlt_properties_set_position( properties, "length", kino_wrapper_get_frame_count( wrapper ) ); mlt_properties_set_position( properties, "in", 0 ); mlt_properties_set_position( properties, "out", kino_wrapper_get_frame_count( wrapper ) - 1 ); mlt_properties_set_double( properties, "real_fps", fps ); mlt_properties_set( properties, "resource", filename ); // Register transport implementation with the producer producer->close = ( mlt_destructor )producer_close; // Register our get_frame implementation with the producer producer->get_frame = producer_get_frame; // Return the producer return producer; } free( this ); } kino_wrapper_close( wrapper ); return NULL; }
int mlt_transition_init( mlt_transition self, void *child ) { mlt_service service = &self->parent; memset( self, 0, sizeof( struct mlt_transition_s ) ); self->child = child; if ( mlt_service_init( service, self ) == 0 ) { mlt_properties properties = MLT_TRANSITION_PROPERTIES( self ); service->get_frame = transition_get_frame; service->close = ( mlt_destructor )mlt_transition_close; service->close_object = self; mlt_properties_set_position( properties, "in", 0 ); mlt_properties_set_position( properties, "out", 0 ); mlt_properties_set_int( properties, "a_track", 0 ); mlt_properties_set_int( properties, "b_track", 1 ); return 0; } return 1; }
static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Get the real structure for this producer producer_qimage self = producer->child; // Fetch the producers properties mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); if ( self->filenames == NULL && mlt_properties_get( producer_properties, "resource" ) != NULL ) load_filenames( self, producer_properties ); // Generate a frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); if ( *frame != NULL && self->count > 0 ) { // Obtain properties of frame and producer mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); // Set the producer on the frame properties mlt_properties_set_data( properties, "producer_qimage", self, 0, NULL, NULL ); // Update timecode on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Ensure that we have a way to obtain the position in the get_image mlt_properties_set_position( properties, "qimage_position", mlt_producer_position( producer ) ); // 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 ); refresh_qimage( self, *frame ); mlt_cache_item_close( self->qimage_cache ); // Set producer-specific frame properties mlt_properties_set_int( properties, "progressive", mlt_properties_get_int( producer_properties, "progressive" ) ); double force_ratio = mlt_properties_get_double( producer_properties, "force_aspect_ratio" ); if ( force_ratio > 0.0 ) mlt_properties_set_double( properties, "aspect_ratio", force_ratio ); else mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( producer_properties, "aspect_ratio" ) ); // Push the get_image method mlt_frame_push_get_image( *frame, producer_get_image ); } // Calculate the next timecode mlt_producer_prepare_next( producer ); return 0; }
mlt_producer producer_qimage_init( mlt_profile profile, mlt_service_type type, const char *id, char *filename ) { producer_qimage self = calloc( sizeof( struct producer_qimage_s ), 1 ); if ( self != NULL && mlt_producer_init( &self->parent, self ) == 0 ) { mlt_producer producer = &self->parent; // Get the properties interface mlt_properties properties = MLT_PRODUCER_PROPERTIES( &self->parent ); // Callback registration #ifdef USE_KDE init_qimage(); #endif producer->get_frame = producer_get_frame; producer->close = ( mlt_destructor )producer_close; // Set the default properties mlt_properties_set( properties, "resource", filename ); mlt_properties_set_int( properties, "ttl", 25 ); mlt_properties_set_int( properties, "aspect_ratio", 1 ); mlt_properties_set_int( properties, "progressive", 1 ); mlt_properties_set_int( properties, "seekable", 1 ); // Validate the resource if ( filename ) load_filenames( self, properties ); if ( self->count ) { mlt_frame frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); if ( frame ) { mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); mlt_properties_set_data( frame_properties, "producer_qimage", self, 0, NULL, NULL ); mlt_frame_set_position( frame, mlt_producer_position( producer ) ); mlt_properties_set_position( frame_properties, "qimage_position", mlt_producer_position( producer ) ); refresh_qimage( self, frame ); mlt_cache_item_close( self->qimage_cache ); mlt_frame_close( frame ); } } if ( self->current_width == 0 ) { producer_close( producer ); producer = NULL; } return producer; } free( self ); return NULL; }
void mlt_multitrack_refresh( mlt_multitrack self ) { int i = 0; // Obtain the properties of this multitrack mlt_properties properties = MLT_MULTITRACK_PROPERTIES( self ); // We need to ensure that the multitrack reports the longest track as its length mlt_position length = 0; // Obtain stats on all connected services for ( i = 0; i < self->count; i ++ ) { // Get the producer from this index mlt_track track = self->list[ i ]; mlt_producer producer = track->producer; // If it's allocated then, update our stats if ( producer != NULL ) { // If we have more than 1 track, we must be in continue mode if ( self->count > 1 ) mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer ), "eof", "continue" ); // Determine the longest length //if ( !mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( producer ), "hide" ) ) length = mlt_producer_get_playtime( producer ) > length ? mlt_producer_get_playtime( producer ) : length; } } // Update multitrack properties now - we'll not destroy the in point here mlt_events_block( properties, properties ); mlt_properties_set_position( properties, "length", length ); mlt_events_unblock( properties, properties ); mlt_properties_set_position( properties, "out", length - 1 ); }
mlt_producer producer_pixbuf_init( char *filename ) { producer_pixbuf this = calloc( sizeof( struct producer_pixbuf_s ), 1 ); if ( this != NULL && mlt_producer_init( &this->parent, this ) == 0 ) { mlt_producer producer = &this->parent; // Get the properties interface mlt_properties properties = MLT_PRODUCER_PROPERTIES( &this->parent ); // Callback registration producer->get_frame = producer_get_frame; producer->close = ( mlt_destructor )producer_close; // Set the default properties mlt_properties_set( properties, "resource", filename ); mlt_properties_set_int( properties, "ttl", 25 ); mlt_properties_set_int( properties, "aspect_ratio", 1 ); mlt_properties_set_int( properties, "progressive", 1 ); // Validate the resource if ( filename ) load_filenames( this, properties ); if ( this->count ) { mlt_frame frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); if ( frame ) { mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); pthread_mutex_init( &this->mutex, NULL ); mlt_properties_set_data( frame_properties, "producer_pixbuf", this, 0, NULL, NULL ); mlt_frame_set_position( frame, mlt_producer_position( producer ) ); mlt_properties_set_position( frame_properties, "pixbuf_position", mlt_producer_position( producer ) ); refresh_image( this, frame, 0, 0 ); mlt_frame_close( frame ); } } if ( this->width == 0 ) { producer_close( producer ); producer = NULL; } return producer; } free( this ); return NULL; }
mlt_frame mlt_filter_process( mlt_filter self, mlt_frame frame ) { mlt_properties properties = MLT_FILTER_PROPERTIES( self ); int disable = mlt_properties_get_int( properties, "disable" ); const char *unique_id = mlt_properties_get( properties, "_unique_id" ); mlt_position position = mlt_frame_get_position( frame ); char name[20]; // Make the properties key from unique id strcpy( name, "pos." ); strcat( name, unique_id ); // Save the position on the frame mlt_properties_set_position( MLT_FRAME_PROPERTIES( frame ), name, position ); if ( disable || self->process == NULL ) return frame; else return self->process( self, frame ); }
static void foreach_consumer_start( mlt_consumer consumer ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); mlt_consumer nested = NULL; char key[30]; int index = 0; do { snprintf( key, sizeof(key), "%d.consumer", index++ ); nested = mlt_properties_get_data( properties, key, NULL ); if ( nested ) { mlt_properties nested_props = MLT_CONSUMER_PROPERTIES(nested); mlt_properties_set_position( nested_props, "_multi_position", 0 ); mlt_properties_set_data( nested_props, "_multi_audio", NULL, 0, NULL, NULL ); mlt_properties_set_int( nested_props, "_multi_samples", 0 ); mlt_consumer_start( nested ); } } while ( nested ); }
static void analyze_audio( mlt_filter filter, void* buffer, int samples ) { mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); private_data* pdata = (private_data*)filter->child; int result = -1; double loudness = 0.0; ebur128_add_frames_float( pdata->r128, buffer, samples ); if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "calc_program" ) ) { result = ebur128_loudness_global( pdata->r128, &loudness ); if( result == EBUR128_SUCCESS && loudness != HUGE_VAL && loudness != -HUGE_VAL ) { mlt_properties_set_double( properties, "program", loudness ); } } if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "calc_shortterm" ) ) { result = ebur128_loudness_shortterm( pdata->r128, &loudness ); if( result == EBUR128_SUCCESS && loudness != HUGE_VAL && loudness != -HUGE_VAL ) { mlt_properties_set_double( properties, "shortterm", loudness ); } } if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "calc_momentary" ) ) { result = ebur128_loudness_momentary( pdata->r128, &loudness ); if( result == EBUR128_SUCCESS && loudness != HUGE_VAL && loudness != -HUGE_VAL ) { mlt_properties_set_double( properties, "momentary", loudness ); } } if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "calc_range" ) ) { double range = 0; result = ebur128_loudness_range( pdata->r128, &range ); if( result == EBUR128_SUCCESS && range != HUGE_VAL && range != -HUGE_VAL ) { mlt_properties_set_double( properties, "range", range ); } } if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "calc_peak" ) ) { double prev_peak = 0.0; double max_peak = 0.0; int c = 0; for( c = 0; c < pdata->r128->channels; c++ ) { double peak; result = ebur128_sample_peak( pdata->r128, c, &peak ); if( result == EBUR128_SUCCESS && peak != HUGE_VAL && peak > max_peak ) { max_peak = peak; } result = ebur128_prev_sample_peak( pdata->r128, c, &peak ); if( result == EBUR128_SUCCESS && peak != HUGE_VAL && peak > prev_peak ) { prev_peak = peak; } } mlt_properties_set_double( properties, "max_peak", 20 * log10(max_peak) ); mlt_properties_set_double( properties, "peak", 20 * log10(prev_peak) ); } if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "calc_true_peak" ) ) { double prev_peak = 0.0; double max_peak = 0.0; int c = 0; for( c = 0; c < pdata->r128->channels; c++ ) { double peak; result = ebur128_true_peak( pdata->r128, c, &peak ); if( result == EBUR128_SUCCESS && peak != HUGE_VAL && peak > max_peak ) { max_peak = peak; } result = ebur128_prev_true_peak( pdata->r128, c, &peak ); if( result == EBUR128_SUCCESS && peak != HUGE_VAL && peak > prev_peak ) { prev_peak = peak; } } mlt_properties_set_double( properties, "max_true_peak", 20 * log10(max_peak) ); mlt_properties_set_double( properties, "true_peak", 20 * log10(prev_peak) ); } mlt_properties_set_position( properties, "frames_processed", mlt_properties_get_position( properties, "frames_processed" ) + 1 ); }
mlt_producer producer_framebuffer_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { if ( !arg ) return NULL; mlt_producer producer = NULL; producer = calloc( 1, sizeof( struct mlt_producer_s ) ); mlt_producer_init( producer, NULL ); // Wrap loader mlt_producer real_producer; // Check if a speed was specified. /** * Speed must be appended to the filename with '?'. To play your video at 50%: melt framebuffer:my_video.mpg?0.5 * Stroboscope effect can be obtained by adding a stobe=x parameter, where x is the number of frames that will be ignored. * You can play the movie backwards by adding reverse=1 * You can freeze the clip at a determined position by adding freeze=frame_pos add freeze_after=1 to freeze only paste position or freeze_before to freeze before it **/ double speed = 0.0; char *props = strdup( arg ); char *ptr = strrchr( props, '?' ); if ( ptr ) { speed = atof( ptr + 1 ); if ( speed != 0.0 ) // If speed was valid, then strip it and the delimiter. // Otherwise, an invalid speed probably means this '?' was not a delimiter. *ptr = '\0'; } real_producer = mlt_factory_producer( profile, "abnormal", props ); free( props ); if (speed == 0.0) speed = 1.0; if ( producer != NULL && real_producer != NULL) { // Get the properties of this producer mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); mlt_properties_set( properties, "resource", arg); // Store the producer and fitler mlt_properties_set_data( properties, "producer", real_producer, 0, ( mlt_destructor )mlt_producer_close, NULL ); // Grab some stuff from the real_producer mlt_properties_pass_list( properties, MLT_PRODUCER_PROPERTIES( real_producer ), "length, width, height, aspect_ratio" ); if ( speed < 0 ) { speed = -speed; mlt_properties_set_int( properties, "reverse", 1 ); } if ( speed != 1.0 ) { double real_length = ( (double) mlt_producer_get_length( real_producer ) ) / speed; mlt_properties_set_position( properties, "length", real_length ); } mlt_properties_set_position( properties, "out", mlt_producer_get_length( producer ) - 1 ); // Since we control the seeking, prevent it from seeking on its own mlt_producer_set_speed( real_producer, 0 ); mlt_producer_set_speed( producer, speed ); // Override the get_frame method producer->get_frame = producer_get_frame; } else { if ( producer ) mlt_producer_close( producer ); if ( real_producer ) mlt_producer_close( real_producer ); producer = NULL; } return producer; }
static mlt_frame transition_process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame ) { mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition ); mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame ); // Only if mix is specified, otherwise a producer may set the mix if ( mlt_properties_get( properties, "start" ) ) { // Determine the time position of this frame in the transition duration mlt_properties props = mlt_properties_get_data( MLT_FRAME_PROPERTIES( b_frame ), "_producer", NULL ); mlt_position in = mlt_properties_get_int( props, "in" ); mlt_position out = mlt_properties_get_int( props, "out" ); int length = mlt_properties_get_int( properties, "length" ); mlt_position time = mlt_properties_get_int( props, "_frame" ); double mix = mlt_transition_get_progress( transition, b_frame ); if ( mlt_properties_get_int( properties, "always_active" ) ) mix = ( double ) ( time - in ) / ( double ) ( out - in + 1 ); // TODO: Check the logic here - shouldn't we be computing current and next mixing levels in all cases? if ( length == 0 ) { // If there is an end mix level adjust mix to the range if ( mlt_properties_get( properties, "end" ) ) { double start = mlt_properties_get_double( properties, "start" ); double end = mlt_properties_get_double( properties, "end" ); mix = start + ( end - start ) * mix; } // A negative means total crossfade (uses position) else if ( mlt_properties_get_double( properties, "start" ) >= 0 ) { // Otherwise, start/constructor is a constant mix level mix = mlt_properties_get_double( properties, "start" ); } // Finally, set the mix property on the frame mlt_properties_set_double( b_props, "audio.mix", mix ); // Initialise transition previous mix value to prevent an inadvertant jump from 0 mlt_position last_position = mlt_properties_get_position( properties, "_last_position" ); mlt_position current_position = mlt_frame_get_position( b_frame ); mlt_properties_set_position( properties, "_last_position", current_position ); if ( !mlt_properties_get( properties, "_previous_mix" ) || current_position != last_position + 1 ) mlt_properties_set_double( properties, "_previous_mix", mix ); // Tell b frame what the previous mix level was mlt_properties_set_double( b_props, "audio.previous_mix", mlt_properties_get_double( properties, "_previous_mix" ) ); // Save the current mix level for the next iteration mlt_properties_set_double( properties, "_previous_mix", mlt_properties_get_double( b_props, "audio.mix" ) ); mlt_properties_set_double( b_props, "audio.reverse", mlt_properties_get_double( properties, "reverse" ) ); } else { double level = mlt_properties_get_double( properties, "start" ); double mix_start = level; double mix_end = mix_start; double mix_increment = 1.0 / length; if ( time - in < length ) { mix_start = mix_start * ( ( double )( time - in ) / length ); mix_end = mix_start + mix_increment; } else if ( time > out - length ) { mix_end = mix_start * ( ( double )( out - time - in ) / length ); mix_start = mix_end - mix_increment; } mix_start = mix_start < 0 ? 0 : mix_start > level ? level : mix_start; mix_end = mix_end < 0 ? 0 : mix_end > level ? level : mix_end; mlt_properties_set_double( b_props, "audio.previous_mix", mix_start ); mlt_properties_set_double( b_props, "audio.mix", mix_end ); } } // Override the get_audio method mlt_frame_push_audio( a_frame, transition ); mlt_frame_push_audio( a_frame, b_frame ); mlt_frame_push_audio( a_frame, transition_get_audio ); return a_frame; }
static int filter_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the filter from the frame mlt_filter this = mlt_frame_pop_audio( frame ); // Get the properties from the filter mlt_properties filter_props = MLT_FILTER_PROPERTIES( this ); // Get the frame's filter instance properties mlt_properties instance_props = mlt_frame_unique_properties( frame, MLT_FILTER_SERVICE( this ) ); // Get the parameters double gain = mlt_properties_get_double( instance_props, "gain" ); double max_gain = mlt_properties_get_double( instance_props, "max_gain" ); double limiter_level = 0.5; /* -6 dBFS */ int normalise = mlt_properties_get_int( instance_props, "normalise" ); double amplitude = mlt_properties_get_double( instance_props, "amplitude" ); int i, j; double sample; int16_t peak; if ( mlt_properties_get( instance_props, "limiter" ) != NULL ) limiter_level = mlt_properties_get_double( instance_props, "limiter" ); // Get the producer's audio *format = mlt_audio_s16; mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); // fprintf( stderr, "filter_volume: frequency %d\n", *frequency ); // Determine numeric limits int bytes_per_samp = (samp_width - 1) / 8 + 1; int samplemax = (1 << (bytes_per_samp * 8 - 1)) - 1; int samplemin = -samplemax - 1; mlt_service_lock( MLT_FILTER_SERVICE( this ) ); if ( normalise ) { int window = mlt_properties_get_int( filter_props, "window" ); double *smooth_buffer = mlt_properties_get_data( filter_props, "smooth_buffer", NULL ); if ( window > 0 && smooth_buffer != NULL ) { int smooth_index = mlt_properties_get_int( filter_props, "_smooth_index" ); // Compute the signal power and put into smoothing buffer smooth_buffer[ smooth_index ] = signal_max_power( *buffer, *channels, *samples, &peak ); // fprintf( stderr, "filter_volume: raw power %f ", smooth_buffer[ smooth_index ] ); if ( smooth_buffer[ smooth_index ] > EPSILON ) { mlt_properties_set_int( filter_props, "_smooth_index", ( smooth_index + 1 ) % window ); // Smooth the data and compute the gain // fprintf( stderr, "smoothed %f over %d frames\n", get_smoothed_data( smooth_buffer, window ), window ); gain *= amplitude / get_smoothed_data( smooth_buffer, window ); } } else { gain *= amplitude / signal_max_power( (int16_t*) *buffer, *channels, *samples, &peak ); } } // if ( gain > 1.0 && normalise ) // fprintf(stderr, "filter_volume: limiter level %f gain %f\n", limiter_level, gain ); if ( max_gain > 0 && gain > max_gain ) gain = max_gain; // Initialise filter's previous gain value to prevent an inadvertant jump from 0 mlt_position last_position = mlt_properties_get_position( filter_props, "_last_position" ); mlt_position current_position = mlt_frame_get_position( frame ); if ( mlt_properties_get( filter_props, "_previous_gain" ) == NULL || current_position != last_position + 1 ) mlt_properties_set_double( filter_props, "_previous_gain", gain ); // Start the gain out at the previous double previous_gain = mlt_properties_get_double( filter_props, "_previous_gain" ); // Determine ramp increment double gain_step = ( gain - previous_gain ) / *samples; // fprintf( stderr, "filter_volume: previous gain %f current gain %f step %f\n", previous_gain, gain, gain_step ); // Save the current gain for the next iteration mlt_properties_set_double( filter_props, "_previous_gain", gain ); mlt_properties_set_position( filter_props, "_last_position", current_position ); mlt_service_unlock( MLT_FILTER_SERVICE( this ) ); // Ramp from the previous gain to the current gain = previous_gain; int16_t *p = (int16_t*) *buffer; // Apply the gain for ( i = 0; i < *samples; i++ ) { for ( j = 0; j < *channels; j++ ) { sample = *p * gain; *p = ROUND( sample ); if ( gain > 1.0 ) { /* use limiter function instead of clipping */ if ( normalise ) *p = ROUND( samplemax * limiter( sample / (double) samplemax, limiter_level ) ); /* perform clipping */ else if ( sample > samplemax ) *p = samplemax; else if ( sample < samplemin ) *p = samplemin; } p++; } gain += gain_step; } return 0; }
static void foreach_consumer_put( mlt_consumer consumer, mlt_frame frame ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); mlt_consumer nested = NULL; char key[30]; int index = 0; do { snprintf( key, sizeof(key), "%d.consumer", index++ ); nested = mlt_properties_get_data( properties, key, NULL ); if ( nested ) { mlt_properties nested_props = MLT_CONSUMER_PROPERTIES(nested); double self_fps = mlt_properties_get_double( properties, "fps" ); double nested_fps = mlt_properties_get_double( nested_props, "fps" ); mlt_position nested_pos = mlt_properties_get_position( nested_props, "_multi_position" ); mlt_position self_pos = mlt_frame_get_position( frame ); double self_time = self_pos / self_fps; double nested_time = nested_pos / nested_fps; // get the audio for the current frame uint8_t *buffer = NULL; mlt_audio_format format = mlt_audio_s16; int channels = mlt_properties_get_int( properties, "channels" ); int frequency = mlt_properties_get_int( properties, "frequency" ); int current_samples = mlt_sample_calculator( self_fps, frequency, self_pos ); mlt_frame_get_audio( frame, (void**) &buffer, &format, &frequency, &channels, ¤t_samples ); int current_size = mlt_audio_format_size( format, current_samples, channels ); // get any leftover audio int prev_size = 0; uint8_t *prev_buffer = mlt_properties_get_data( nested_props, "_multi_audio", &prev_size ); uint8_t *new_buffer = NULL; if ( prev_size > 0 ) { new_buffer = mlt_pool_alloc( prev_size + current_size ); memcpy( new_buffer, prev_buffer, prev_size ); memcpy( new_buffer + prev_size, buffer, current_size ); buffer = new_buffer; } current_size += prev_size; current_samples += mlt_properties_get_int( nested_props, "_multi_samples" ); while ( nested_time <= self_time ) { // put ideal number of samples into cloned frame int deeply = index > 1 ? 1 : 0; mlt_frame clone_frame = mlt_frame_clone( frame, deeply ); int nested_samples = mlt_sample_calculator( nested_fps, frequency, nested_pos ); // -10 is an optimization to avoid tiny amounts of leftover samples nested_samples = nested_samples > current_samples - 10 ? current_samples : nested_samples; int nested_size = mlt_audio_format_size( format, nested_samples, channels ); if ( nested_size > 0 ) { prev_buffer = mlt_pool_alloc( nested_size ); memcpy( prev_buffer, buffer, nested_size ); } else { prev_buffer = NULL; nested_size = 0; } mlt_frame_set_audio( clone_frame, prev_buffer, format, nested_size, mlt_pool_release ); mlt_properties_set_int( MLT_FRAME_PROPERTIES(clone_frame), "audio_samples", nested_samples ); mlt_properties_set_int( MLT_FRAME_PROPERTIES(clone_frame), "audio_frequency", frequency ); mlt_properties_set_int( MLT_FRAME_PROPERTIES(clone_frame), "audio_channels", channels ); // chomp the audio current_samples -= nested_samples; current_size -= nested_size; buffer += nested_size; // send frame to nested consumer mlt_consumer_put_frame( nested, clone_frame ); mlt_properties_set_position( nested_props, "_multi_position", ++nested_pos ); nested_time = nested_pos / nested_fps; } // save any remaining audio if ( current_size > 0 ) { prev_buffer = mlt_pool_alloc( current_size ); memcpy( prev_buffer, buffer, current_size ); } else { prev_buffer = NULL; current_size = 0; } mlt_pool_release( new_buffer ); mlt_properties_set_data( nested_props, "_multi_audio", prev_buffer, current_size, mlt_pool_release, NULL ); mlt_properties_set_int( nested_props, "_multi_samples", current_samples ); } } while ( nested ); }