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; }
mlt_frame mlt_consumer_get_frame( mlt_consumer self ) { // Frame to return mlt_frame frame = NULL; // Get the service assoicated to the consumer mlt_service service = MLT_CONSUMER_SERVICE( self ); // Get the consumer properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); // Get the frame if ( mlt_service_producer( service ) == NULL && mlt_properties_get_int( properties, "put_mode" ) ) { struct timeval now; struct timespec tm; pthread_mutex_lock( &self->put_mutex ); while ( self->put_active && self->put == NULL ) { gettimeofday( &now, NULL ); tm.tv_sec = now.tv_sec + 1; tm.tv_nsec = now.tv_usec * 1000; pthread_cond_timedwait( &self->put_cond, &self->put_mutex, &tm ); } frame = self->put; self->put = NULL; pthread_cond_broadcast( &self->put_cond ); pthread_mutex_unlock( &self->put_mutex ); if ( frame != NULL ) mlt_service_apply_filters( service, frame, 0 ); } else if ( mlt_service_producer( service ) != NULL ) { mlt_service_get_frame( service, &frame, 0 ); } else { frame = mlt_frame_init( service ); } if ( frame != NULL ) { // Get the frame properties mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); // Get the test card producer mlt_producer test_card = mlt_properties_get_data( properties, "test_card_producer", NULL ); // Attach the test frame producer to it. if ( test_card != NULL ) mlt_properties_set_data( frame_properties, "test_card_producer", test_card, 0, NULL, NULL ); // Pass along the interpolation and deinterlace options // TODO: get rid of consumer_deinterlace and use profile.progressive mlt_properties_set( frame_properties, "rescale.interp", mlt_properties_get( properties, "rescale" ) ); mlt_properties_set_int( frame_properties, "consumer_deinterlace", mlt_properties_get_int( properties, "progressive" ) | mlt_properties_get_int( properties, "deinterlace" ) ); mlt_properties_set( frame_properties, "deinterlace_method", mlt_properties_get( properties, "deinterlace_method" ) ); mlt_properties_set_int( frame_properties, "consumer_tff", mlt_properties_get_int( properties, "top_field_first" ) ); } // Return the frame return frame; }
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 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; } }
static int framebuffer_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the filter object and properties mlt_producer producer = mlt_frame_pop_service( frame ); int index = mlt_frame_pop_service_int( frame ); mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) ); // Frame properties objects mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); mlt_frame first_frame = mlt_properties_get_data( properties, "first_frame", NULL ); // Get producer parameters int strobe = mlt_properties_get_int( properties, "strobe" ); int freeze = mlt_properties_get_int( properties, "freeze" ); int freeze_after = mlt_properties_get_int( properties, "freeze_after" ); int freeze_before = mlt_properties_get_int( properties, "freeze_before" ); int in = mlt_properties_get_position( properties, "in" ); // Determine the position mlt_position first_position = (first_frame != NULL) ? mlt_frame_get_position( first_frame ) : -1; mlt_position need_first = freeze; if ( !freeze || freeze_after || freeze_before ) { double prod_speed = mlt_properties_get_double( properties, "_speed" ); double actual_position = in + prod_speed * (double) mlt_producer_position( producer ); if ( mlt_properties_get_int( properties, "reverse" ) ) actual_position = mlt_producer_get_playtime( producer ) - actual_position; if ( strobe < 2 ) { need_first = floor( actual_position ); } else { // Strobe effect wanted, calculate frame position need_first = floor( actual_position ); need_first -= MLT_POSITION_MOD(need_first, strobe); } if ( freeze ) { if ( freeze_after && need_first > freeze ) need_first = freeze; else if ( freeze_before && need_first < freeze ) need_first = freeze; } } // Determine output buffer size *width = mlt_properties_get_int( frame_properties, "width" ); *height = mlt_properties_get_int( frame_properties, "height" ); int size = mlt_image_format_size( *format, *width, *height, NULL ); // Get output buffer int buffersize = 0; int alphasize = *width * *height; uint8_t *output = mlt_properties_get_data( properties, "output_buffer", &buffersize ); uint8_t *output_alpha = mlt_properties_get_data( properties, "output_alpha", NULL ); if( buffersize == 0 || buffersize != size ) { // invalidate cached frame first_position = -1; } if ( need_first != first_position ) { // invalidate cached frame first_position = -1; // Bust the cached frame mlt_properties_set_data( properties, "first_frame", NULL, 0, NULL, NULL ); first_frame = NULL; } if ( output && first_position != -1 ) { // Using the cached frame uint8_t *image_copy = mlt_pool_alloc( size ); memcpy( image_copy, output, size ); uint8_t *alpha_copy = mlt_pool_alloc( alphasize ); memcpy( alpha_copy, output_alpha, alphasize ); // Set the output image *image = image_copy; mlt_frame_set_image( frame, image_copy, size, mlt_pool_release ); mlt_frame_set_alpha( frame, alpha_copy, alphasize, mlt_pool_release ); *width = mlt_properties_get_int( properties, "_output_width" ); *height = mlt_properties_get_int( properties, "_output_height" ); *format = mlt_properties_get_int( properties, "_output_format" ); mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); return 0; } // Get the cached frame 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, need_first ); // 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 first_frame_properties = MLT_FRAME_PROPERTIES( first_frame ); // Which frames are buffered? uint8_t *first_image = mlt_properties_get_data( first_frame_properties, "image", NULL ); uint8_t *first_alpha = mlt_properties_get_data( first_frame_properties, "alpha", NULL ); if ( !first_image ) { mlt_properties_set( first_frame_properties, "rescale.interp", mlt_properties_get( frame_properties, "rescale.interp" ) ); int error = mlt_frame_get_image( first_frame, &first_image, format, width, height, writable ); if ( error != 0 ) { mlt_log_warning( MLT_PRODUCER_SERVICE( producer ), "first_image == NULL get image died\n" ); mlt_properties_set_data( properties, "first_frame", NULL, 0, NULL, NULL ); mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); return error; } output = mlt_pool_alloc( size ); memcpy( output, first_image, size ); // Let someone else clean up mlt_properties_set_data( properties, "output_buffer", output, size, mlt_pool_release, NULL ); mlt_properties_set_int( properties, "_output_width", *width ); mlt_properties_set_int( properties, "_output_height", *height ); mlt_properties_set_int( properties, "_output_format", *format ); } if ( !first_alpha ) { alphasize = *width * *height; first_alpha = mlt_frame_get_alpha_mask( first_frame ); output_alpha = mlt_pool_alloc( alphasize ); memcpy( output_alpha, first_alpha, alphasize ); mlt_properties_set_data( properties, "output_alpha", output_alpha, alphasize, mlt_pool_release, NULL ); } mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); // Create a copy uint8_t *image_copy = mlt_pool_alloc( size ); memcpy( image_copy, first_image, size ); uint8_t *alpha_copy = mlt_pool_alloc( alphasize ); memcpy( alpha_copy, first_alpha, alphasize ); // Set the output image *image = image_copy; mlt_frame_set_image( frame, *image, size, mlt_pool_release ); mlt_frame_set_alpha( frame, alpha_copy, alphasize, mlt_pool_release ); return 0; }
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; }
static int generate_test_image( mlt_properties properties, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { mlt_producer producer = mlt_properties_get_data( properties, "test_card_producer", NULL ); mlt_image_format requested_format = *format; int error = 1; if ( producer ) { mlt_frame test_frame = NULL; mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &test_frame, 0 ); if ( test_frame ) { mlt_properties test_properties = MLT_FRAME_PROPERTIES( test_frame ); mlt_properties_set_data( properties, "test_card_frame", test_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); mlt_properties_set( test_properties, "rescale.interp", mlt_properties_get( properties, "rescale.interp" ) ); error = mlt_frame_get_image( test_frame, buffer, format, width, height, writable ); if ( !error && buffer && *buffer ) { mlt_properties_set_double( properties, "aspect_ratio", mlt_frame_get_aspect_ratio( test_frame ) ); mlt_properties_set_int( properties, "width", *width ); mlt_properties_set_int( properties, "height", *height ); if ( test_frame->convert_image && requested_format != mlt_image_none ) test_frame->convert_image( test_frame, buffer, format, requested_format ); mlt_properties_set_int( properties, "format", *format ); } } else { mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL ); } } if ( error && buffer && *format != mlt_image_none ) { int size = 0; *width = *width == 0 ? 720 : *width; *height = *height == 0 ? 576 : *height; size = *width * *height; mlt_properties_set_int( properties, "format", *format ); mlt_properties_set_int( properties, "width", *width ); mlt_properties_set_int( properties, "height", *height ); mlt_properties_set_double( properties, "aspect_ratio", 1.0 ); switch( *format ) { case mlt_image_rgb24: size *= 3; size += *width * 3; *buffer = mlt_pool_alloc( size ); if ( *buffer ) memset( *buffer, 255, size ); break; case mlt_image_rgb24a: case mlt_image_opengl: size *= 4; size += *width * 4; *buffer = mlt_pool_alloc( size ); if ( *buffer ) memset( *buffer, 255, size ); break; case mlt_image_yuv422: size *= 2; size += *width * 2; *buffer = mlt_pool_alloc( size ); if ( *buffer ) { register uint8_t *p = *buffer; register uint8_t *q = p + size; while ( p != NULL && p != q ) { *p ++ = 235; *p ++ = 128; } } break; case mlt_image_yuv420p: *buffer = mlt_pool_alloc( size * 3 / 2 ); if ( *buffer ) { memset( *buffer, 235, size ); memset( *buffer + size, 128, size / 2 ); } break; default: size = 0; break; } mlt_properties_set_data( properties, "image", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL ); mlt_properties_set_int( properties, "test_image", 1 ); error = 0; } return error; }
static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); mlt_position pos = mlt_filter_get_position( filter, frame ); mlt_position len = mlt_filter_get_length2( filter, frame ); int maxdia = mlt_properties_anim_get_int( properties, "maxdiameter", pos, len ); int maxcount = mlt_properties_anim_get_int( properties, "maxcount", pos, len ); *format = mlt_image_yuv422; int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); // Load svg char *factory = mlt_properties_get( properties, "factory" ); char temp[1204] = ""; sprintf( temp, "%s/oldfilm/", mlt_environment( "MLT_DATA" ) ); mlt_properties direntries = mlt_properties_new(); mlt_properties_dir_list( direntries, temp,"dust*.svg",1 ); if (!maxcount) return 0; double position = mlt_filter_get_progress( filter, frame ); srand( position * 10000 ); mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); int im = rand() % maxcount; int piccount = mlt_properties_count( direntries ); while ( im-- && piccount ) { int picnum = rand() % piccount; int y1 = rand() % *height; int x1 = rand() % *width; char resource[1024] = ""; char savename[1024] = "", savename1[1024] = "", cachedy[100]; int dx = ( *width * maxdia / 100); int luma_width, luma_height; uint8_t *luma_image = NULL; uint8_t *alpha = NULL; int updown = rand() % 2; int mirror = rand() % 2; sprintf( resource, "%s", mlt_properties_get_value(direntries,picnum) ); sprintf( savename, "cache-%d-%d", picnum,dx ); sprintf( savename1, "cache-alpha-%d-%d", picnum, dx ); sprintf( cachedy, "cache-dy-%d-%d", picnum,dx ); luma_image = mlt_properties_get_data( properties , savename , NULL ); alpha = mlt_properties_get_data( properties , savename1 , NULL ); if ( luma_image == NULL || alpha == NULL ) { mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); mlt_producer producer = mlt_factory_producer( profile, factory, resource ); if ( producer != NULL ) { mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); mlt_properties_set( producer_properties, "eof", "loop" ); mlt_frame luma_frame = NULL; if ( mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &luma_frame, 0 ) == 0 ) { mlt_image_format luma_format = mlt_image_yuv422; luma_width = dx; luma_height = luma_width * mlt_properties_get_int( MLT_FRAME_PROPERTIES ( luma_frame ) , "height" ) / mlt_properties_get_int( MLT_FRAME_PROPERTIES ( luma_frame ) , "width" ); mlt_properties_set( MLT_FRAME_PROPERTIES( luma_frame ), "rescale.interp", "best" );// none/nearest/tiles/hyper mlt_frame_get_image( luma_frame, &luma_image, &luma_format, &luma_width, &luma_height, 0 ); alpha = mlt_frame_get_alpha_mask (luma_frame ); uint8_t* savealpha = mlt_pool_alloc( luma_width * luma_height ); uint8_t* savepic = mlt_pool_alloc( luma_width * luma_height * 2); if ( savealpha && savepic ) { memcpy( savealpha, alpha , luma_width * luma_height ); memcpy( savepic, luma_image , luma_width * luma_height * 2 ); mlt_properties_set_data( properties, savename, savepic, luma_width * luma_height * 2, mlt_pool_release, NULL ); mlt_properties_set_data( properties, savename1, savealpha, luma_width * luma_height, mlt_pool_release, NULL ); mlt_properties_set_int( properties, cachedy, luma_height ); overlay_image( *image, *width, *height, luma_image, luma_width, luma_height, alpha, x1, y1, updown, mirror ); } else { if ( savealpha ) mlt_pool_release( savealpha ); if ( savepic ) mlt_pool_release( savepic ); } mlt_frame_close( luma_frame ); } mlt_producer_close( producer ); } } else { overlay_image ( *image, *width, *height, luma_image, dx, mlt_properties_get_int ( properties, cachedy ), alpha, x1, y1, updown, mirror ); } } mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); if (piccount>0 ) return 0; if ( error == 0 && *image ) { int h = *height; int w = *width; int im = rand() % maxcount; while ( im-- ) { int type = im % 2; int y1 = rand() % h; int x1 = rand() % w; int dx = rand() % maxdia; int dy = rand() % maxdia; int x=0, y=0; double v = 0.0; for ( x = -dx ; x < dx ; x++ ) { for ( y = -dy ; y < dy ; y++ ) { if ( x1 + x < w && x1 + x > 0 && y1 + y < h && y1 + y > 0 ){ uint8_t *pix = *image + (y+y1) * w * 2 + (x + x1) * 2; v=pow((double) x /(double)dx * 5.0, 2.0) + pow((double)y / (double)dy * 5.0, 2.0); if (v>10) v=10; v = 1.0 - ( v / 10.0 ); switch(type) { case 0: *pix -= (*pix) * v; break; case 1: *pix += ( 255-*pix ) * v; break; } } } } } } 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_frame( mlt_service service, mlt_frame_ptr frame, int index ) { int error = 0; mlt_transition self = service->child; mlt_properties properties = MLT_TRANSITION_PROPERTIES( self ); int accepts_blanks = mlt_properties_get_int( properties, "accepts_blanks" ); int a_track = mlt_properties_get_int( properties, "a_track" ); int b_track = mlt_properties_get_int( properties, "b_track" ); mlt_position in = mlt_properties_get_position( properties, "in" ); mlt_position out = mlt_properties_get_position( properties, "out" ); int always_active = mlt_properties_get_int( properties, "always_active" ); int type = mlt_properties_get_int( properties, "_transition_type" ); int reverse_order = 0; // Ensure that we have the correct order if ( a_track > b_track ) { reverse_order = 1; a_track = b_track; b_track = mlt_properties_get_int( properties, "a_track" ); } // Only act on this operation once per multitrack iteration from the tractor if ( !self->held ) { int active = 0; int i = 0; int a_frame = a_track; int b_frame = b_track; mlt_position position; int ( *invalid )( mlt_frame ) = type == 1 ? mlt_frame_is_test_card : mlt_frame_is_test_audio; // Initialise temporary store if ( self->frames == NULL ) self->frames = calloc( b_track + 1, sizeof( mlt_frame ) ); // Get all frames between a and b for( i = a_track; i <= b_track; i ++ ) mlt_service_get_frame( self->producer, &self->frames[ i ], i ); // We're holding these frames until the last_track frame property is received self->held = 1; // When we need to locate the a_frame switch( type ) { case 1: case 2: // Some transitions (esp. audio) may accept blank frames active = accepts_blanks; // If we're not active then... if ( !active ) { // Hunt for the a_frame while( a_frame <= b_frame && invalid( self->frames[ a_frame ] ) ) a_frame ++; // Determine if we're active now active = a_frame != b_frame && !invalid( self->frames[ b_frame ] ); } break; default: mlt_log( service, MLT_LOG_ERROR, "invalid transition type\n" ); break; } // Now handle the non-always active case if ( active && !always_active && a_frame <= b_track ) { // For non-always-active transitions, we need the current position of the a frame position = mlt_frame_get_position( self->frames[ a_frame ] ); // If a is in range, we're active active = position >= in && ( out == 0 || position <= out ); } // Finally, process the a and b frames if ( active && !mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( self ), "disable" ) ) { int frame_nb = ( !reverse_order && a_frame <= b_track )? a_frame : b_frame; mlt_frame a_frame_ptr = self->frames[ frame_nb ]; frame_nb = ( !reverse_order || a_frame > b_track )? b_frame : a_frame; mlt_frame b_frame_ptr = self->frames[ frame_nb ]; int a_hide = mlt_properties_get_int( MLT_FRAME_PROPERTIES( a_frame_ptr ), "hide" ); int b_hide = mlt_properties_get_int( MLT_FRAME_PROPERTIES( b_frame_ptr ), "hide" ); if ( !( a_hide & type ) && !( b_hide & type ) ) { // Add hooks for pre-processing frames mlt_frame_push_service( a_frame_ptr, self ); mlt_frame_push_get_image( a_frame_ptr, get_image_a ); mlt_frame_push_frame( b_frame_ptr, a_frame_ptr ); mlt_frame_push_service( b_frame_ptr, self ); mlt_frame_push_get_image( b_frame_ptr, get_image_b ); // Process the transition *frame = mlt_transition_process( self, a_frame_ptr, b_frame_ptr ); // We need to ensure that the tractor doesn't consider this frame for output if ( *frame == a_frame_ptr ) b_hide |= type; else a_hide |= type; mlt_properties_set_int( MLT_FRAME_PROPERTIES( a_frame_ptr ), "hide", a_hide ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( b_frame_ptr ), "hide", b_hide ); } } } // Obtain the frame from the cache or the producer we're attached to if ( index >= a_track && index <= b_track ) *frame = self->frames[ index ]; else error = mlt_service_get_frame( self->producer, frame, index ); // Determine if that was the last track self->held = !mlt_properties_get_int( MLT_FRAME_PROPERTIES( *frame ), "last_track" ); return error; }
static mlt_frame get_text_frame( mlt_producer producer, time_info* info ) { mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); mlt_producer text_producer = mlt_properties_get_data( producer_properties, "_text_producer", NULL ); mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ); mlt_frame text_frame = NULL; if( !text_producer ) { text_producer = mlt_factory_producer( profile, mlt_environment( "MLT_PRODUCER" ), "qtext:" ); // Save the producer for future use. mlt_properties_set_data( producer_properties, "_text_producer", text_producer, 0, ( mlt_destructor )mlt_producer_close, NULL ); // Calculate the font size. char font_size[MAX_TEXT_LEN]; snprintf( font_size, MAX_TEXT_LEN - 1, "%dpx", profile->height * TEXT_SIZE_RATIO / 100 ); // Configure the producer. mlt_properties text_properties = MLT_PRODUCER_PROPERTIES( text_producer ); mlt_properties_set( text_properties, "size", font_size ); mlt_properties_set( text_properties, "weight", "400" ); mlt_properties_set( text_properties, "fgcolour", TEXT_FOREGROUND_COLOR ); mlt_properties_set( text_properties, "bgcolour", TEXT_BACKGROUND_COLOR ); mlt_properties_set( text_properties, "pad", "0" ); mlt_properties_set( text_properties, "outline", "0" ); mlt_properties_set( text_properties, "align", "center" ); } if( text_producer ) { mlt_properties text_properties = MLT_PRODUCER_PROPERTIES( text_producer ); char* style = mlt_properties_get( producer_properties, "style" ); char text[MAX_TEXT_LEN] = ""; // Apply the time style if( !strcmp( style, "frames" ) ) { snprintf( text, MAX_TEXT_LEN - 1, MLT_POSITION_FMT, info->position ); } else if( !strcmp( style, "timecode" ) ) { snprintf( text, MAX_TEXT_LEN - 1, "%02d:%02d:%02d%c%0*d", info->hours, info->minutes, info->seconds, info->sep, ( info->fps > 999? 4 : info->fps > 99? 3 : 2 ), info->frames ); } else if( !strcmp( style, "clock" ) ) { snprintf( text, MAX_TEXT_LEN - 1, "%.2d:%.2d:%.2d", info->hours, info->minutes, info->seconds ); } else if( !strcmp( style, "seconds+1" ) ) { snprintf( text, MAX_TEXT_LEN - 1, "%d", info->seconds + 1 ); } else // seconds { snprintf( text, MAX_TEXT_LEN - 1, "%d", info->seconds ); } mlt_properties_set( text_properties, "text", text ); // Get the frame. mlt_service_get_frame( MLT_PRODUCER_SERVICE( text_producer ), &text_frame, 0 ); } return text_frame; }
int mlt_frame_get_image( mlt_frame self, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { mlt_properties properties = MLT_FRAME_PROPERTIES( self ); mlt_get_image get_image = mlt_frame_pop_get_image( self ); mlt_producer producer = mlt_properties_get_data( properties, "test_card_producer", NULL ); mlt_image_format requested_format = *format; int error = 0; if ( get_image ) { mlt_properties_set_int( properties, "image_count", mlt_properties_get_int( properties, "image_count" ) - 1 ); error = get_image( self, buffer, format, width, height, writable ); if ( !error && *buffer ) { mlt_properties_set_int( properties, "width", *width ); mlt_properties_set_int( properties, "height", *height ); if ( self->convert_image && *buffer && requested_format != mlt_image_none ) self->convert_image( self, buffer, format, requested_format ); mlt_properties_set_int( properties, "format", *format ); } else { // Cause the image to be loaded from test card or fallback (white) below. mlt_frame_get_image( self, buffer, format, width, height, writable ); } } else if ( mlt_properties_get_data( properties, "image", NULL ) ) { *format = mlt_properties_get_int( properties, "format" ); *buffer = mlt_properties_get_data( properties, "image", NULL ); *width = mlt_properties_get_int( properties, "width" ); *height = mlt_properties_get_int( properties, "height" ); if ( self->convert_image && *buffer && requested_format != mlt_image_none ) { self->convert_image( self, buffer, format, requested_format ); mlt_properties_set_int( properties, "format", *format ); } } else if ( producer ) { mlt_frame test_frame = NULL; mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &test_frame, 0 ); if ( test_frame ) { mlt_properties test_properties = MLT_FRAME_PROPERTIES( test_frame ); mlt_properties_set( test_properties, "rescale.interp", mlt_properties_get( properties, "rescale.interp" ) ); mlt_frame_get_image( test_frame, buffer, format, width, height, writable ); mlt_properties_set_data( properties, "test_card_frame", test_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); mlt_properties_set_double( properties, "aspect_ratio", mlt_frame_get_aspect_ratio( test_frame ) ); // mlt_properties_set_data( properties, "image", *buffer, *width * *height * 2, NULL, NULL ); // mlt_properties_set_int( properties, "width", *width ); // mlt_properties_set_int( properties, "height", *height ); // mlt_properties_set_int( properties, "format", *format ); } else { mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL ); mlt_frame_get_image( self, buffer, format, width, height, writable ); } } else { register uint8_t *p; register uint8_t *q; int size = 0; *width = *width == 0 ? 720 : *width; *height = *height == 0 ? 576 : *height; size = *width * *height; mlt_properties_set_int( properties, "format", *format ); mlt_properties_set_int( properties, "width", *width ); mlt_properties_set_int( properties, "height", *height ); mlt_properties_set_int( properties, "aspect_ratio", 0 ); switch( *format ) { case mlt_image_none: size = 0; *buffer = NULL; break; case mlt_image_rgb24: size *= 3; size += *width * 3; *buffer = mlt_pool_alloc( size ); if ( *buffer ) memset( *buffer, 255, size ); break; case mlt_image_rgb24a: case mlt_image_opengl: size *= 4; size += *width * 4; *buffer = mlt_pool_alloc( size ); if ( *buffer ) memset( *buffer, 255, size ); break; case mlt_image_yuv422: size *= 2; size += *width * 2; *buffer = mlt_pool_alloc( size ); p = *buffer; q = p + size; while ( p != NULL && p != q ) { *p ++ = 235; *p ++ = 128; } break; case mlt_image_yuv420p: size = size * 3 / 2; *buffer = mlt_pool_alloc( size ); if ( *buffer ) memset( *buffer, 255, size ); break; } mlt_properties_set_data( properties, "image", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL ); mlt_properties_set_int( properties, "test_image", 1 ); } return error; }