static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index ) { // Get the mutiltrack object mlt_multitrack self = parent->child; // Check if we have a track for this index if ( index >= 0 && index < self->count && self->list[ index ] != NULL ) { // Get the producer for this track mlt_producer producer = self->list[ index ]->producer; // Get the track hide property int hide = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( producer ) ), "hide" ); // Obtain the current position mlt_position position = mlt_producer_frame( parent ); // Get the parent properties mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( parent ); // Get the speed double speed = mlt_properties_get_double( producer_properties, "_speed" ); // Make sure we're at the same point mlt_producer_seek( producer, position ); // Get the frame from the producer mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), frame, 0 ); // Indicate speed of this producer mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); mlt_properties_set_double( properties, "_speed", speed ); mlt_frame_set_position( *frame, position ); mlt_properties_set_int( properties, "hide", hide ); } else { // Generate a test frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( parent ) ); // Update position on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( parent ) ); // Move on to the next frame if ( index >= self->count ) { // Let tractor know if we've reached the end mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "last_track", 1 ); // Move to the next frame mlt_producer_prepare_next( parent ); } } return 0; }
/** Get the image. */ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { int error = 0; mlt_filter filter = mlt_frame_pop_service( frame ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); mlt_producer producer = mlt_properties_get_data( properties, "_producer", NULL ); mlt_transition transition = mlt_properties_get_data( properties, "_transition", NULL ); mlt_frame text_frame = NULL; mlt_position position = 0; // Configure this filter mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); setup_producer( filter, producer, frame ); setup_transition( filter, transition ); mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); // Make sure the producer is in the correct position position = mlt_filter_get_position( filter, frame ); mlt_producer_seek( producer, position ); // Get the b frame and process with transition if successful if ( mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &text_frame, 0 ) == 0 ) { // Get the a and b frame properties mlt_properties a_props = MLT_FRAME_PROPERTIES( frame ); mlt_properties b_props = MLT_FRAME_PROPERTIES( text_frame ); // Set the frame and text_frame to be in the same position and have same consumer requirements mlt_frame_set_position( text_frame, position ); mlt_frame_set_position( frame, position ); mlt_properties_set_int( b_props, "consumer_deinterlace", mlt_properties_get_int( a_props, "consumer_deinterlace" ) ); // Apply all filters that are attached to this filter to the b frame mlt_service_apply_filters( MLT_FILTER_SERVICE( filter ), text_frame, 0 ); // Process the frame mlt_transition_process( transition, frame, text_frame ); // Get the image *format = mlt_image_yuv422; error = mlt_frame_get_image( frame, image, format, width, height, 1 ); // Close the b frame mlt_frame_close( text_frame ); } return error; }
static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Generate a frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); // Check that we created a frame and initialize it if ( *frame != NULL ) { // Obtain properties of frame mlt_properties frame_properties = MLT_FRAME_PROPERTIES( *frame ); // Update timecode on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Save the producer to be used in get_audio mlt_properties_set_data( frame_properties, "_producer_ladspa", producer, 0, NULL, NULL ); // Push the get_audio method mlt_frame_push_audio( *frame, producer_get_audio ); } // Calculate the next time code mlt_producer_prepare_next( producer ); return 0; }
int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Generate a frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); if ( *frame != NULL ) { // Obtain properties of frame and producer mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); // Obtain properties of producer mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer ); // Set the producer on the frame properties mlt_properties_set_data( properties, "producer_frei0r", producer, 0, NULL, NULL ); // Update timecode on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Set producer-specific frame properties mlt_properties_set_int( properties, "progressive", 1 ); mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ); mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile ) ); // 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; }
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; }
static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Generate a frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ); if ( *frame != NULL ) { // Obtain properties of frame mlt_properties frame_properties = MLT_FRAME_PROPERTIES( *frame ); // Update time code on the frame mlt_frame_set_position( *frame, mlt_producer_frame( producer ) ); mlt_properties_set_int( frame_properties, "progressive", 1 ); mlt_properties_set_double( frame_properties, "aspect_ratio", mlt_profile_sar( profile ) ); mlt_properties_set_int( frame_properties, "meta.media.width", profile->width ); mlt_properties_set_int( frame_properties, "meta.media.height", profile->height ); // Configure callbacks mlt_frame_push_service( *frame, producer ); mlt_frame_push_get_image( *frame, producer_get_image ); mlt_frame_push_audio( *frame, producer ); mlt_frame_push_audio( *frame, producer_get_audio ); } // Calculate the next time code 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; }
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; }
static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Generate a frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); if ( *frame != NULL ) { mlt_properties frame_properties = MLT_FRAME_PROPERTIES( *frame ); mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); // Regenerate the QPainterPath if necessary if( check_qpath( producer_properties ) ) { generate_qpath( producer_properties ); } // Give the frame a copy of the painter path QPainterPath* prodPath = static_cast<QPainterPath*>( mlt_properties_get_data( producer_properties, "_qpath", NULL ) ); QPainterPath* framePath = new QPainterPath( *prodPath ); mlt_properties_set_data( frame_properties, "_qpath", static_cast<void*>( framePath ), 0, close_qpath, NULL ); // Pass properties to the frame that will be needed to render the path mlt_properties_set( frame_properties, "_path_sig", mlt_properties_get( producer_properties, "_path_sig" ) ); mlt_properties_set( frame_properties, "_bgcolour", mlt_properties_get( producer_properties, "bgcolour" ) ); mlt_properties_set( frame_properties, "_fgcolour", mlt_properties_get( producer_properties, "fgcolour" ) ); mlt_properties_set( frame_properties, "_olcolour", mlt_properties_get( producer_properties, "olcolour" ) ); mlt_properties_set( frame_properties, "_outline", mlt_properties_get( producer_properties, "outline" ) ); mlt_properties_set_data( frame_properties, "_producer_qtext", static_cast<void*>( producer ), 0, NULL, NULL ); // Set frame properties mlt_properties_set_int( frame_properties, "progressive", 1 ); double force_ratio = mlt_properties_get_double( producer_properties, "force_aspect_ratio" ); if ( force_ratio > 0.0 ) mlt_properties_set_double( frame_properties, "aspect_ratio", force_ratio ); else mlt_properties_set_double( frame_properties, "aspect_ratio", 1.0); // Update time code on the frame mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Configure callbacks mlt_frame_push_get_image( *frame, producer_get_image ); } // Calculate the next time code mlt_producer_prepare_next( producer ); return 0; }
static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { if ( frame ) { // Construct a new frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); // Stack the producer and producer's get image mlt_frame_push_service_int( *frame, index ); mlt_frame_push_service( *frame, producer ); mlt_frame_push_service( *frame, framebuffer_get_image ); mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); mlt_properties frame_properties = MLT_FRAME_PROPERTIES(*frame); // Get frame from the real producer mlt_frame first_frame = mlt_properties_get_data( properties, "first_frame", NULL ); if ( first_frame == NULL ) { // Get the frame to cache from the real producer mlt_producer real_producer = mlt_properties_get_data( properties, "producer", NULL ); // Seek the producer to the correct place mlt_producer_seek( real_producer, mlt_producer_position( producer ) ); // Get the frame mlt_service_get_frame( MLT_PRODUCER_SERVICE( real_producer ), &first_frame, index ); // Cache the frame mlt_properties_set_data( properties, "first_frame", first_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); } mlt_properties_inherit( frame_properties, MLT_FRAME_PROPERTIES(first_frame) ); double force_aspect_ratio = mlt_properties_get_double( properties, "force_aspect_ratio" ); if ( force_aspect_ratio <= 0.0 ) force_aspect_ratio = mlt_properties_get_double( properties, "aspect_ratio" ); mlt_properties_set_double( frame_properties, "aspect_ratio", force_aspect_ratio ); // Give the returned frame temporal identity mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); mlt_properties_set_int( frame_properties, "meta.media.width", mlt_properties_get_int( properties, "width" ) ); mlt_properties_set_int( frame_properties, "meta.media.height", mlt_properties_get_int( properties, "height" ) ); mlt_properties_pass_list( frame_properties, properties, "width, height" ); } return 0; }
mlt_producer producer_pixbuf_init( char *filename ) { producer_pixbuf self = calloc( 1, sizeof( struct producer_pixbuf_s ) ); 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 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 ); mlt_properties_set_int( properties, "loop", 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_pixbuf", self, 0, NULL, NULL ); mlt_frame_set_position( frame, mlt_producer_position( producer ) ); refresh_pixbuf( self, frame ); mlt_cache_item_close( self->pixbuf_cache ); mlt_frame_close( frame ); } } if ( self->width == 0 ) { producer_close( producer ); producer = NULL; } return producer; } free( self ); return NULL; }
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; }
static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { producer_kino this = producer->child; uint8_t *data = mlt_pool_alloc( FRAME_SIZE_625_50 ); // Obtain the current frame number uint64_t position = mlt_producer_frame( producer ); // Create an empty frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); // Seek and fetch if ( kino_wrapper_get_frame( this->wrapper, data, position ) ) { // Get the frames properties mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); // Determine if we're PAL or NTSC int is_pal = kino_wrapper_is_pal( this->wrapper ); // Pass the dv data mlt_properties_set_data( properties, "dv_data", data, FRAME_SIZE_625_50, ( mlt_destructor )mlt_pool_release, NULL ); // Update other info on the frame mlt_properties_set_int( properties, "width", 720 ); mlt_properties_set_int( properties, "height", is_pal ? 576 : 480 ); mlt_properties_set_int( properties, "top_field_first", is_pal ? 0 : ( data[ 5 ] & 0x07 ) == 0 ? 0 : 1 ); } else { mlt_pool_release( data ); } // Update timecode on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Calculate the next timecode mlt_producer_prepare_next( producer ); return 0; }
static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Get the real structure for this producer producer_ktitle this = producer->child; /* Generate a frame */ *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); if ( *frame != NULL ) { /* Obtain properties of frame and producer */ mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); /* Obtain properties of producer */ mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer ); /* Set the producer on the frame properties */ mlt_properties_set_data( properties, "producer_kdenlivetitle", this, 0, NULL, NULL ); /* Update timecode on the frame we're creating */ mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Set producer-specific frame properties mlt_properties_set_int( properties, "progressive", mlt_properties_get_int( producer_props, "progressive" ) ); double force_ratio = mlt_properties_get_double( producer_props, "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_props, "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; }
static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the filter mlt_filter filter = mlt_frame_pop_service( frame ); // Get the properties of the filter mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); // Get the region transition mlt_transition transition = mlt_properties_get_data( properties, "_transition", NULL ); // Create the transition if not available if ( transition == NULL ) { // Create the transition mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); transition = mlt_factory_transition( profile, "region", NULL ); // Register with the filter mlt_properties_set_data( properties, "_transition", transition, 0, ( mlt_destructor )mlt_transition_close, NULL ); // Pass a reference to this filter down mlt_properties_set_data( MLT_TRANSITION_PROPERTIES( transition ), "_region_filter", filter, 0, NULL, NULL ); } mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); // Pass all properties down mlt_properties_inherit( MLT_TRANSITION_PROPERTIES( transition ), properties ); // Make the frame's position relative to this filter's in point mlt_frame_set_position( frame, mlt_filter_get_position( filter, frame ) ); // Process the frame mlt_transition_process( transition, frame, NULL ); return mlt_frame_get_image( frame, image, format, width, height, writable ); }
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; }
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; }
static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Error we will return int error = 0; // Get the watermark filter object mlt_filter this = mlt_frame_pop_service( frame ); // Get the properties of the filter mlt_properties properties = MLT_FILTER_PROPERTIES( this ); mlt_service_lock( MLT_FILTER_SERVICE( this ) ); // Get the producer from the filter mlt_producer producer = mlt_properties_get_data( properties, "producer", NULL ); // Get the composite from the filter mlt_transition composite = mlt_properties_get_data( properties, "composite", NULL ); // Get the resource to use char *resource = mlt_properties_get( properties, "resource" ); // Get the old resource char *old_resource = mlt_properties_get( properties, "_old_resource" ); // Create a composite if we don't have one if ( composite == NULL ) { // Create composite via the factory mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( this ) ); composite = mlt_factory_transition( profile, "composite", NULL ); // Register the composite for reuse/destruction if ( composite != NULL ) mlt_properties_set_data( properties, "composite", composite, 0, ( mlt_destructor )mlt_transition_close, NULL ); } // If we have one if ( composite != NULL ) { // Get the properties mlt_properties composite_properties = MLT_TRANSITION_PROPERTIES( composite ); // Pass all the composite. properties on the filter down mlt_properties_pass( composite_properties, properties, "composite." ); if ( mlt_properties_get( properties, "composite.out" ) == NULL ) mlt_properties_set_int( composite_properties, "out", mlt_properties_get_int( properties, "_out" ) ); // Force a refresh mlt_properties_set_int( composite_properties, "refresh", 1 ); } // Create a producer if don't have one if ( producer == NULL || ( old_resource != NULL && strcmp( resource, old_resource ) ) ) { // Get the factory producer service char *factory = mlt_properties_get( properties, "factory" ); // Create the producer mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( this ) ); producer = mlt_factory_producer( profile, factory, resource ); // If we have one if ( producer != NULL ) { // Register the producer for reuse/destruction mlt_properties_set_data( properties, "producer", producer, 0, ( mlt_destructor )mlt_producer_close, NULL ); // Ensure that we loop mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer ), "eof", "loop" ); // Set the old resource mlt_properties_set( properties, "_old_resource", resource ); } } if ( producer != NULL ) { // Get the producer properties mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); // Now pass all producer. properties on the filter down mlt_properties_pass( producer_properties, properties, "producer." ); } mlt_service_unlock( MLT_FILTER_SERVICE( this ) ); // Only continue if we have both producer and composite if ( composite != NULL && producer != NULL ) { // Get the service of the producer mlt_service service = MLT_PRODUCER_SERVICE( producer ); // We will get the 'b frame' from the producer mlt_frame b_frame = NULL; // Get the original producer position mlt_position position = mlt_filter_get_position( this, frame ); // Make sure the producer is in the correct position mlt_producer_seek( producer, position ); // Resetting position to appease the composite transition mlt_frame_set_position( frame, position ); // Get the b frame and process with composite if successful if ( mlt_service_get_frame( service, &b_frame, 0 ) == 0 ) { // Get the a and b frame properties mlt_properties a_props = MLT_FRAME_PROPERTIES( frame ); mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame ); mlt_profile profile = mlt_service_profile( service ); // Set the b frame to be in the same position and have same consumer requirements mlt_frame_set_position( b_frame, position ); mlt_properties_set_int( b_props, "consumer_deinterlace", mlt_properties_get_int( a_props, "consumer_deinterlace" ) || mlt_properties_get_int( properties, "deinterlace" ) ); // Check for the special case - no aspect ratio means no problem :-) if ( mlt_frame_get_aspect_ratio( b_frame ) == 0 ) mlt_frame_set_aspect_ratio( b_frame, mlt_profile_sar( profile ) ); if ( mlt_frame_get_aspect_ratio( frame ) == 0 ) mlt_frame_set_aspect_ratio( frame, mlt_profile_sar( profile ) ); if ( mlt_properties_get_int( properties, "distort" ) ) { mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( composite ), "distort", 1 ); mlt_properties_set_int( a_props, "distort", 1 ); mlt_properties_set_int( b_props, "distort", 1 ); } *format = mlt_image_yuv422; if ( mlt_properties_get_int( properties, "reverse" ) == 0 ) { // Apply all filters that are attached to this filter to the b frame mlt_service_apply_filters( MLT_FILTER_SERVICE( this ), b_frame, 0 ); // Process the frame mlt_transition_process( composite, frame, b_frame ); // Get the image error = mlt_frame_get_image( frame, image, format, width, height, 1 ); } else { char temp[ 132 ]; int count = 0; uint8_t *alpha = NULL; const char *rescale = mlt_properties_get( a_props, "rescale.interp" ); if ( rescale == NULL || !strcmp( rescale, "none" ) ) rescale = "hyper"; mlt_transition_process( composite, b_frame, frame ); mlt_properties_set_int( a_props, "consumer_deinterlace", 1 ); mlt_properties_set_int( b_props, "consumer_deinterlace", 1 ); mlt_properties_set( a_props, "rescale.interp", rescale ); mlt_properties_set( b_props, "rescale.interp", rescale ); mlt_service_apply_filters( MLT_FILTER_SERVICE( this ), b_frame, 0 ); error = mlt_frame_get_image( b_frame, image, format, width, height, 1 ); alpha = mlt_frame_get_alpha_mask( b_frame ); mlt_frame_set_image( frame, *image, *width * *height * 2, NULL ); mlt_frame_set_alpha( frame, alpha, *width * *height, NULL ); mlt_properties_set_int( a_props, "width", *width ); mlt_properties_set_int( a_props, "height", *height ); mlt_properties_set_int( a_props, "progressive", 1 ); mlt_properties_inc_ref( b_props ); strcpy( temp, "_b_frame" ); while( mlt_properties_get_data( a_props, temp, NULL ) != NULL ) sprintf( temp, "_b_frame%d", count ++ ); mlt_properties_set_data( a_props, temp, b_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); } } // Close the b frame mlt_frame_close( b_frame ); } else { // Get the image from the frame without running fx error = mlt_frame_get_image( frame, image, format, width, height, 1 ); } return error; }
static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the filter mlt_filter filter = mlt_frame_pop_service( frame ); // Get the properties mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); // Get the image int error = 0; *format = mlt_image_rgb24a; // Only process if we have no error and a valid colour space if ( error == 0 ) { mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); mlt_producer producer = mlt_properties_get_data( properties, "producer", NULL ); mlt_transition transition = mlt_properties_get_data( properties, "transition", NULL ); mlt_frame a_frame = NULL; mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); if ( producer == NULL ) { char *background = mlt_properties_get( properties, "background" ); producer = mlt_factory_producer( profile, NULL, background ); mlt_properties_set_data( properties, "producer", producer, 0, (mlt_destructor)mlt_producer_close, NULL ); } if ( transition == NULL ) { transition = mlt_factory_transition( profile, "qtblend", NULL ); mlt_properties_set_data( properties, "transition", transition, 0, (mlt_destructor)mlt_transition_close, NULL ); if ( transition ) mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( transition ), "b_alpha", 1 ); } if ( producer != NULL && transition != NULL ) { mlt_position position = mlt_filter_get_position( filter, frame ); mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); mlt_position in = mlt_filter_get_in( filter ); mlt_position out = mlt_filter_get_out( filter ); double consumer_ar = mlt_profile_sar( profile ); mlt_transition_set_in_and_out( transition, in, out ); if ( out > 0 ) { mlt_properties_set_position( MLT_PRODUCER_PROPERTIES( producer ), "length", out - in + 1 ); mlt_producer_set_in_and_out( producer, in, out ); } mlt_producer_seek( producer, in + position ); mlt_frame_set_position( frame, position ); mlt_properties_pass( MLT_PRODUCER_PROPERTIES( producer ), properties, "producer." ); mlt_properties_pass( MLT_TRANSITION_PROPERTIES( transition ), properties, "transition." ); mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &a_frame, 0 ); mlt_frame_set_position( a_frame, in + position ); // Set the rescale interpolation to match the frame mlt_properties_set( MLT_FRAME_PROPERTIES( a_frame ), "rescale.interp", mlt_properties_get( frame_properties, "rescale.interp" ) ); // Special case - aspect_ratio = 0 if ( mlt_frame_get_aspect_ratio( frame ) == 0 ) mlt_frame_set_aspect_ratio( frame, consumer_ar ); if ( mlt_frame_get_aspect_ratio( a_frame ) == 0 ) mlt_frame_set_aspect_ratio( a_frame, consumer_ar ); // Add the qtblend transition onto the frame stack mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); mlt_transition_process( transition, a_frame, frame ); if ( mlt_properties_get_int( properties, "use_normalised" ) ) { // Use the normalised width & height mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); *width = profile->width; *height = profile->height; } mlt_frame_get_image( a_frame, image, format, width, height, writable ); mlt_properties_set_data( frame_properties, "affine_frame", a_frame, 0, (mlt_destructor)mlt_frame_close, NULL ); mlt_frame_set_image( frame, *image, *width * *height * 4, NULL ); //mlt_frame_set_alpha( frame, mlt_frame_get_alpha_mask( a_frame ), *width * *height, NULL ); } else { mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); } } return error; }
static int transition_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Error we will return int error = 0; // We will get the 'b frame' from the frame stack mlt_frame b_frame = mlt_frame_pop_frame( frame ); // Get the watermark transition object mlt_transition transition = mlt_frame_pop_service( frame ); // Get the properties of the transitionfin mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition ); // Get the properties of the a frame mlt_properties a_props = MLT_FRAME_PROPERTIES( frame ); mlt_service_lock( MLT_TRANSITION_SERVICE( transition ) ); // Get the composite from the transition mlt_transition composite = mlt_properties_get_data( properties, "composite", NULL ); // Look for the first filter mlt_filter filter = mlt_properties_get_data( properties, "_filter_0", NULL ); // Get the position mlt_position position = mlt_transition_get_position( transition, frame ); // Create a composite if we don't have one if ( composite == NULL ) { // Create composite via the factory mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( transition ) ); composite = mlt_factory_transition( profile, "composite", NULL ); // If we have one if ( composite != NULL ) { // Get the properties mlt_properties composite_properties = MLT_TRANSITION_PROPERTIES( composite ); // We want to ensure that we don't get a wobble... //mlt_properties_set_int( composite_properties, "distort", 1 ); mlt_properties_set_int( composite_properties, "progressive", 1 ); // Pass all the composite. properties on the transition down mlt_properties_pass( composite_properties, properties, "composite." ); // Register the composite for reuse/destruction mlt_properties_set_data( properties, "composite", composite, 0, ( mlt_destructor )mlt_transition_close, NULL ); } } else { // Pass all current properties down mlt_properties composite_properties = MLT_TRANSITION_PROPERTIES( composite ); mlt_properties_pass( composite_properties, properties, "composite." ); } // Create filters if ( filter == NULL ) { // Loop Variable int i = 0; // Number of filters created int count = 0; // Loop for all properties for ( i = 0; i < mlt_properties_count( properties ); i ++ ) { // Get the name of this property char *name = mlt_properties_get_name( properties, i ); // If the name does not contain a . and matches filter if ( strchr( name, '.' ) == NULL && !strncmp( name, "filter", 6 ) ) { // Get the filter constructor char *value = mlt_properties_get_value( properties, i ); // Create an instance if ( create_instance( transition, name, value, count ) == 0 ) count ++; } } // Look for the first filter again filter = mlt_properties_get_data( properties, "_filter_0", NULL ); } else { // Pass all properties down mlt_filter temp = NULL; // Loop Variable int i = 0; // Number of filters found int count = 0; // Loop for all properties for ( i = 0; i < mlt_properties_count( properties ); i ++ ) { // Get the name of this property char *name = mlt_properties_get_name( properties, i ); // If the name does not contain a . and matches filter if ( strchr( name, '.' ) == NULL && !strncmp( name, "filter", 6 ) ) { // Strings to hold the id and pass down key char id[ 256 ]; char key[ 256 ]; // Construct id and key sprintf( id, "_filter_%d", count ); sprintf( key, "%s.", name ); // Get the filter temp = mlt_properties_get_data( properties, id, NULL ); if ( temp != NULL ) { mlt_properties_pass( MLT_FILTER_PROPERTIES( temp ), properties, key ); count ++; } } } } mlt_properties_set_int( a_props, "width", *width ); mlt_properties_set_int( a_props, "height", *height ); // Only continue if we have both filter and composite if ( composite != NULL ) { // Get the resource of this filter (could be a shape [rectangle/circle] or an alpha provider of choice const char *resource = mlt_properties_get( properties, "resource" ); // Get the old resource in case it's changed char *old_resource = mlt_properties_get( properties, "_old_resource" ); // String to hold the filter to query on char id[ 256 ]; // Index to hold the count int i = 0; // We will get the 'b frame' from the composite only if it's NULL (region filter) if ( b_frame == NULL ) { // Copy the region b_frame = composite_copy_region( composite, frame, position ); // Ensure a destructor char *name = mlt_properties_get( properties, "_unique_id" ); mlt_properties_set_data( a_props, name, b_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); } // Properties of the B framr mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame ); // filter_only prevents copying the alpha channel of the shape to the output frame // by compositing filtered frame over itself if ( mlt_properties_get_int( properties, "filter_only" ) ) { char *name = mlt_properties_get( properties, "_unique_id" ); frame = composite_copy_region( composite, b_frame, position ); mlt_properties_set_data( b_props, name, frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); } // Make sure the filter is in the correct position while ( filter != NULL ) { // Stack this filter if ( mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "off" ) == 0 ) mlt_filter_process( filter, b_frame ); // Generate the key for the next sprintf( id, "_filter_%d", ++ i ); // Get the next filter filter = mlt_properties_get_data( properties, id, NULL ); } // Allow filters to be attached to a region filter filter = mlt_properties_get_data( properties, "_region_filter", NULL ); if ( filter != NULL ) mlt_service_apply_filters( MLT_FILTER_SERVICE( filter ), b_frame, 0 ); // Hmm - this is probably going to go wrong.... mlt_frame_set_position( frame, position ); // Get the b frame and process with composite if successful mlt_transition_process( composite, frame, b_frame ); // If we have a shape producer copy the alpha mask from the shape frame to the b_frame if ( strcmp( resource, "rectangle" ) != 0 ) { // Get the producer from the transition mlt_producer producer = mlt_properties_get_data( properties, "producer", NULL ); // If We have no producer then create one if ( producer == NULL || ( old_resource != NULL && strcmp( resource, old_resource ) ) ) { // Get the factory producer service char *factory = mlt_properties_get( properties, "factory" ); // Store the old resource mlt_properties_set( properties, "_old_resource", resource ); // Special case circle resource if ( strcmp( resource, "circle" ) == 0 ) resource = "pixbuf:<svg width='100' height='100'><circle cx='50' cy='50' r='50' fill='black'/></svg>"; // Create the producer mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( transition ) ); producer = mlt_factory_producer( profile, factory, resource ); // If we have one if ( producer != NULL ) { // Get the producer properties mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); // Ensure that we loop mlt_properties_set( producer_properties, "eof", "loop" ); // Now pass all producer. properties on the transition down mlt_properties_pass( producer_properties, properties, "producer." ); // Register the producer for reuse/destruction mlt_properties_set_data( properties, "producer", producer, 0, ( mlt_destructor )mlt_producer_close, NULL ); } } // Now use the shape producer if ( producer != NULL ) { // We will get the alpha frame from the producer mlt_frame shape_frame = NULL; // Make sure the producer is in the correct position mlt_producer_seek( producer, position ); // Get the shape frame if ( mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &shape_frame, 0 ) == 0 ) { // Ensure that the shape frame will be closed mlt_properties_set_data( b_props, "shape_frame", shape_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); if ( mlt_properties_get_int(properties, "holecolor") ) { mlt_properties_set_int(b_props, "holecolor", mlt_properties_get_int(properties,"holecolor")); } // Specify the callback for evaluation b_frame->get_alpha_mask = filter_get_alpha_mask; } } } // Get the image error = mlt_frame_get_image( frame, image, format, width, height, 0 ); } mlt_service_unlock( MLT_TRANSITION_SERVICE( transition ) ); return error; }
mlt_frame getFrame() { struct timeval now; struct timespec tm; double fps = mlt_producer_get_fps( getProducer() ); mlt_position position = mlt_producer_position( getProducer() ); mlt_frame frame = mlt_cache_get_frame( m_cache, position ); // Allow the buffer to fill to the requested initial buffer level. if ( m_isBuffering ) { int prefill = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "prefill" ); int buffer = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "buffer" ); m_isBuffering = false; prefill = prefill > buffer ? buffer : prefill; pthread_mutex_lock( &m_mutex ); while ( mlt_deque_count( m_queue ) < prefill ) { // Wait up to buffer/fps seconds gettimeofday( &now, NULL ); long usec = now.tv_sec * 1000000 + now.tv_usec; usec += 1000000 * buffer / fps; tm.tv_sec = usec / 1000000; tm.tv_nsec = (usec % 1000000) * 1000; if ( pthread_cond_timedwait( &m_condition, &m_mutex, &tm ) ) break; } pthread_mutex_unlock( &m_mutex ); } if ( !frame ) { // Wait if queue is empty pthread_mutex_lock( &m_mutex ); while ( mlt_deque_count( m_queue ) < 1 ) { // Wait up to twice frame duration gettimeofday( &now, NULL ); long usec = now.tv_sec * 1000000 + now.tv_usec; usec += 2000000 / fps; tm.tv_sec = usec / 1000000; tm.tv_nsec = (usec % 1000000) * 1000; if ( pthread_cond_timedwait( &m_condition, &m_mutex, &tm ) ) // Stop waiting if error (timed out) break; } frame = ( mlt_frame ) mlt_deque_pop_front( m_queue ); pthread_mutex_unlock( &m_mutex ); // add to cache if ( frame ) { mlt_frame_set_position( frame, position ); mlt_cache_put_frame( m_cache, frame ); } } // Set frame timestamp and properties if ( frame ) { mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) ); mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); mlt_properties_set_int( properties, "progressive", profile->progressive ); mlt_properties_set_int( properties, "meta.media.progressive", profile->progressive ); mlt_properties_set_int( properties, "top_field_first", m_topFieldFirst ); mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile ) ); mlt_properties_set_int( properties, "meta.media.sample_aspect_num", profile->sample_aspect_num ); mlt_properties_set_int( properties, "meta.media.sample_aspect_den", profile->sample_aspect_den ); mlt_properties_set_int( properties, "meta.media.frame_rate_num", profile->frame_rate_num ); mlt_properties_set_int( properties, "meta.media.frame_rate_den", profile->frame_rate_den ); mlt_properties_set_int( properties, "width", profile->width ); mlt_properties_set_int( properties, "meta.media.width", profile->width ); mlt_properties_set_int( properties, "height", profile->height ); mlt_properties_set_int( properties, "meta.media.height", profile->height ); mlt_properties_set_int( properties, "format", mlt_image_yuv422 ); mlt_properties_set_int( properties, "colorspace", m_colorspace ); mlt_properties_set_int( properties, "meta.media.colorspace", m_colorspace ); mlt_properties_set_int( properties, "audio_frequency", 48000 ); mlt_properties_set_int( properties, "audio_channels", mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" ) ); } else mlt_log_warning( getProducer(), "buffer underrun\n" ); return frame; }
static int process_feed( mlt_properties feed, mlt_filter filter, mlt_frame frame ) { // Error return int error = 1; // Get the properties of the data show filter mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); // Get the type requested by the feeding filter char *type = mlt_properties_get( feed, "type" ); // Fetch the filter associated to this type mlt_filter requested = mlt_properties_get_data( filter_properties, type, NULL ); // If it doesn't exist, then create it now if ( requested == NULL ) { // Source filter from profile requested = obtain_filter( filter, type ); // Store it on the properties for subsequent retrieval/destruction mlt_properties_set_data( filter_properties, type, requested, 0, ( mlt_destructor )mlt_filter_close, NULL ); } // If we have one, then process it now... if ( requested != NULL ) { int i = 0; mlt_properties properties = MLT_FILTER_PROPERTIES( requested ); static const char *prefix = "properties."; int len = strlen( prefix ); // Determine if this is an absolute or relative feed int absolute = mlt_properties_get_int( feed, "absolute" ); // Make do with what we have int length = !absolute ? mlt_properties_get_int( feed, "out" ) - mlt_properties_get_int( feed, "in" ) + 1 : mlt_properties_get_int( feed, "out" ) + 1; // Repeat period int period = mlt_properties_get_int( properties, "period" ); period = period == 0 ? 1 : period; // Pass properties from feed into requested for ( i = 0; i < mlt_properties_count( properties ); i ++ ) { char *name = mlt_properties_get_name( properties, i ); char *key = mlt_properties_get_value( properties, i ); if ( !strncmp( name, prefix, len ) ) { if ( !strncmp( name + len, "length[", 7 ) ) { mlt_properties_set_position( properties, key, ( length - period ) / period ); } else { char *value = mlt_properties_get( feed, name + len ); if ( value != NULL ) { // check for metadata keywords in metadata markup if user requested so if ( mlt_properties_get_int( filter_properties, "dynamic" ) == 1 && !strcmp( name + strlen( name ) - 6, "markup") ) { // Find keywords which should be surrounded by '#', like: #title# char* keywords = strtok( value, "#" ); char result[512] = ""; // XXX: how much is enough? int ct = 0; int fromStart = ( value[0] == '#' ) ? 1 : 0; while ( keywords != NULL ) { if ( ct % 2 == fromStart ) { // backslash in front of # suppresses substitution if ( keywords[ strlen( keywords ) -1 ] == '\\' ) { // keep characters except backslash strncat( result, keywords, sizeof( result ) - strlen( result ) - 2 ); strcat( result, "#" ); ct++; } else { strncat( result, keywords, sizeof( result ) - strlen( result ) - 1 ); } } else if ( !strcmp( keywords, "timecode" ) ) { // special case: replace #timecode# with current frame timecode mlt_position frames = mlt_properties_get_position( feed, "position" ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); char *s = mlt_properties_frames_to_time( properties, frames, mlt_time_smpte_df ); if ( s ) strncat( result, s, sizeof( result ) - strlen( result ) - 1 ); } else if ( !strcmp( keywords, "frame" ) ) { // special case: replace #frame# with current frame number int pos = mlt_properties_get_int( feed, "position" ); char s[12]; snprintf( s, sizeof(s) - 1, "%d", pos ); s[sizeof( s ) - 1] = '\0'; strncat( result, s, sizeof( result ) - strlen( result ) - 1 ); } else { // replace keyword with metadata value char *metavalue = metadata_value( MLT_FRAME_PROPERTIES( frame ), keywords ); strncat( result, metavalue ? metavalue : "-", sizeof( result ) - strlen( result ) -1 ); } keywords = strtok( NULL, "#" ); ct++; } mlt_properties_set( properties, key, (char*) result ); } else mlt_properties_set( properties, key, value ); } } } } // Set the original position on the frame if ( absolute == 0 ) mlt_frame_set_position( frame, mlt_properties_get_int( feed, "position" ) - mlt_properties_get_int( feed, "in" ) ); else mlt_frame_set_position( frame, mlt_properties_get_int( feed, "position" ) ); // Process the filter mlt_filter_process( requested, frame ); // Should be ok... error = 0; } return error; }
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; } }