static void add_text_to_bg( mlt_producer producer, mlt_frame bg_frame, mlt_frame text_frame ) { mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); mlt_transition transition = mlt_properties_get_data( producer_properties, "_transition", NULL ); if( !transition ) { mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ); transition = mlt_factory_transition( profile, "composite", NULL ); // Save the transition for future use. mlt_properties_set_data( producer_properties, "_transition", transition, 0, ( mlt_destructor )mlt_transition_close, NULL ); // Configure the transition. mlt_properties transition_properties = MLT_TRANSITION_PROPERTIES( transition ); mlt_properties_set( transition_properties, "geometry", "0%/0%:100%x100%:100" ); mlt_properties_set( transition_properties, "halign", "center" ); mlt_properties_set( transition_properties, "valign", "middle" ); } if( transition && bg_frame && text_frame ) { // Apply the transition. mlt_transition_process( transition, bg_frame, text_frame ); } }
mlt_producer create_tracks( int argc, char **argv ) { // Create the field mlt_field field = mlt_field_init( ); // Obtain the multitrack mlt_multitrack multitrack = mlt_field_multitrack( field ); // Obtain the tractor mlt_tractor tractor = mlt_field_tractor( field ); // Obtain a composite transition mlt_transition transition = mlt_factory_transition( "composite", "10%,10%:15%x15%" ); // Create track 0 mlt_producer track0 = create_playlist( argc, argv ); // Get the length of track0 mlt_position length = mlt_producer_get_playtime( track0 ); // Create the watermark track mlt_producer track1 = mlt_factory_producer( NULL, "pango:" ); // Get the properties of track1 mlt_properties properties = mlt_producer_properties( track1 ); // Set the properties mlt_properties_set( properties, "text", "Hello\nWorld" ); mlt_properties_set_position( properties, "in", 0 ); mlt_properties_set_position( properties, "out", length - 1 ); mlt_properties_set_position( properties, "length", length ); // Now set the properties on the transition properties = mlt_transition_properties( transition ); mlt_properties_set_position( properties, "in", 0 ); mlt_properties_set_position( properties, "out", length - 1 ); // Add our tracks to the multitrack mlt_multitrack_connect( multitrack, track0, 0 ); mlt_multitrack_connect( multitrack, track1, 1 ); // Now plant the transition mlt_field_plant_transition( field, transition, 0, 1 ); // Now set the properties on the transition properties = mlt_tractor_properties( tractor ); // Ensure clean up and set properties correctly mlt_properties_set_data( properties, "multitrack", multitrack, 0, ( mlt_destructor )mlt_multitrack_close, NULL ); mlt_properties_set_data( properties, "field", field, 0, ( mlt_destructor )mlt_field_close, NULL ); mlt_properties_set_data( properties, "track0", track0, 0, ( mlt_destructor )mlt_producer_close, NULL ); mlt_properties_set_data( properties, "track1", track1, 0, ( mlt_destructor )mlt_producer_close, NULL ); mlt_properties_set_data( properties, "transition", transition, 0, ( mlt_destructor )mlt_transition_close, NULL ); mlt_properties_set_position( properties, "length", length ); mlt_properties_set_position( properties, "out", length - 1 ); // Return the tractor return mlt_tractor_producer( tractor ); }
static mlt_frame process(mlt_filter filter, mlt_frame frame) { mlt_properties properties = MLT_FILTER_PROPERTIES(filter); mlt_transition transition = mlt_properties_get_data(properties, "instance", NULL); char *name = mlt_properties_get(MLT_FILTER_PROPERTIES(filter), "transition"); if (!name || !strcmp("", name)) return frame; // Create the transition if needed. if (!transition || !mlt_properties_get(MLT_FILTER_PROPERTIES(transition), "mlt_service") || strcmp(name, mlt_properties_get(MLT_FILTER_PROPERTIES(transition), "mlt_service"))) { mlt_profile profile = mlt_service_profile(MLT_FILTER_SERVICE(filter)); transition = mlt_factory_transition(profile, name, NULL); mlt_properties_set_data(MLT_FILTER_PROPERTIES(filter), "instance", transition, 0, (mlt_destructor) mlt_transition_close, NULL); } if (transition) { mlt_properties transition_props = MLT_TRANSITION_PROPERTIES(transition); int type = mlt_properties_get_int(transition_props, "_transition_type"); int hide = mlt_properties_get_int(MLT_FRAME_PROPERTIES(frame), "hide"); mlt_properties_pass_list(transition_props, properties, "in out"); mlt_properties_pass(transition_props, properties, "transition." ); // Only if video transition on visible track. if ((type & 1) && !mlt_frame_is_test_card(frame) && !(hide & 1)) { mlt_frame_push_service_int(frame, mlt_image_format_id(mlt_properties_get(properties, "mlt_image_format"))); mlt_frame_push_service(frame, transition); mlt_frame_push_get_image(frame, get_image); } if (type == 0) mlt_properties_debug(transition_props, "unknown transition type", stderr); } else { mlt_properties_debug(properties, "mask_failed to create transition", stderr ); } return frame; }
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 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; }
/** Constructor for the filter. */ mlt_filter filter_dynamictext_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = mlt_filter_new(); mlt_transition transition = mlt_factory_transition( profile, "composite", NULL ); mlt_producer producer = mlt_factory_producer( profile, mlt_environment( "MLT_PRODUCER" ), "qtext:" ); // Use pango if qtext is not available. if( !producer ) producer = mlt_factory_producer( profile, mlt_environment( "MLT_PRODUCER" ), "pango:" ); if ( filter && transition && producer ) { mlt_properties my_properties = MLT_FILTER_PROPERTIES( filter ); // Register the transition for reuse/destruction mlt_properties_set_data( my_properties, "_transition", transition, 0, ( mlt_destructor )mlt_transition_close, NULL ); // Register the producer for reuse/destruction mlt_properties_set_data( my_properties, "_producer", producer, 0, ( mlt_destructor )mlt_producer_close, NULL ); // Ensure that we loop mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer ), "eof", "loop" ); // Assign default values mlt_properties_set( my_properties, "argument", arg ? arg: "#timecode#" ); mlt_properties_set( my_properties, "geometry", "0%/0%:100%x100%:100" ); mlt_properties_set( my_properties, "family", "Sans" ); mlt_properties_set( my_properties, "size", "48" ); mlt_properties_set( my_properties, "weight", "400" ); mlt_properties_set( my_properties, "fgcolour", "0x000000ff" ); mlt_properties_set( my_properties, "bgcolour", "0x00000020" ); mlt_properties_set( my_properties, "olcolour", "0x00000000" ); mlt_properties_set( my_properties, "pad", "0" ); mlt_properties_set( my_properties, "halign", "left" ); mlt_properties_set( my_properties, "valign", "top" ); mlt_properties_set( my_properties, "outline", "0" ); mlt_properties_set_int( my_properties, "_filter_private", 1 ); filter->process = filter_process; } else { if( filter ) { mlt_filter_close( filter ); } if( transition ) { mlt_transition_close( transition ); } if( producer ) { mlt_producer_close( producer ); } filter = NULL; } return filter; }
int main( int argc, char **argv ) { char temp[ 132 ]; char *file1 = NULL; char *file2 = NULL; char *wipe = NULL; mlt_factory_init( "../modules" ); if ( argc < 4 ) { fprintf( stderr, "usage: luma file1.mpeg file2.mpeg wipe.pgm\n" ); return 1; } else { file1 = argv[ 1 ]; file2 = argv[ 2 ]; wipe = argv[ 3 ]; } // Start the consumer... mlt_consumer consumer = mlt_factory_consumer( "bluefish", "NTSC" ); // Create the producer(s) mlt_producer dv1 = mlt_factory_producer( "mcmpeg", file1 ); mlt_producer dv2 = mlt_factory_producer( "mcmpeg", file2 ); mlt_playlist playlist1 = mlt_playlist_init(); mlt_playlist_append_io( playlist1, dv1, 0.0, 5.0 ); mlt_playlist playlist2 = mlt_playlist_init(); mlt_playlist_blank( playlist2, 2.9 ); mlt_playlist_append( playlist2, dv2 ); // Register producers(s) with a multitrack object mlt_multitrack multitrack = mlt_multitrack_init( ); mlt_multitrack_connect( multitrack, mlt_playlist_producer( playlist1 ), 0 ); mlt_multitrack_connect( multitrack, mlt_playlist_producer( playlist2 ), 1 ); // Define a transition mlt_transition transition = mlt_factory_transition( "luma", wipe ); mlt_properties_set( mlt_transition_properties( transition ), "filename", wipe ); mlt_properties_set_double( mlt_transition_properties( transition ), "softness", 0.1 ); mlt_transition_connect( transition, mlt_multitrack_service( multitrack ), 0, 1 ); mlt_transition_set_in_and_out( transition, 3.0, 5.0 ); // Buy a tractor and connect it to the filter mlt_tractor tractor = mlt_tractor_init( ); mlt_tractor_connect( tractor, mlt_transition_service( transition ) ); // Connect the tractor to the consumer mlt_consumer_connect( consumer, mlt_tractor_service( tractor ) ); // Do stuff until we're told otherwise... fprintf( stderr, "Press return to continue\n" ); fgets( temp, 132, stdin ); // Close everything... mlt_consumer_close( consumer ); mlt_tractor_close( tractor ); mlt_transition_close( transition ); mlt_multitrack_close( multitrack ); mlt_playlist_close( playlist1 ); mlt_playlist_close( playlist2 ); mlt_producer_close( dv1 ); mlt_producer_close( dv2 ); 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 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; }
int main( int argc, char **argv ) { char temp[ 132 ]; char *file1 = NULL; char *text = NULL; mlt_factory_init( "../modules" ); if ( argc < 3 ) { fprintf( stderr, "usage: pango file.mpeg text_to_display\n" ); return 1; } else { file1 = argv[ 1 ]; text = argv[ 2 ]; } // Start the consumer... mlt_consumer consumer = mlt_factory_consumer( "bluefish", "NTSC" ); // Create the producer(s) mlt_playlist pl1 = mlt_playlist_init(); mlt_producer dv1 = mlt_factory_producer( "mcmpeg", file1 ); mlt_playlist_append( pl1, dv1 ); mlt_playlist pl2 = mlt_playlist_init(); mlt_producer title = mlt_factory_producer( "pango", NULL ); //"<span font_desc=\"Sans Bold 36\">Mutton <span font_desc=\"Luxi Serif Bold Oblique 36\">Lettuce</span> Tomato</span>" ); mlt_playlist_append( pl2, title ); mlt_properties_set( mlt_producer_properties( title ), "family", "Sans" ); mlt_properties_set( mlt_producer_properties( title ), "size", "36" ); mlt_properties_set( mlt_producer_properties( title ), "weight", "700" ); mlt_properties_set( mlt_producer_properties( title ), "text", text ); mlt_properties_set_int( mlt_producer_properties( title ), "bgcolor", 0x0000007f ); mlt_properties_set_int( mlt_producer_properties( title ), "pad", 8 ); mlt_properties_set_int( mlt_producer_properties( title ), "align", 1 ); mlt_properties_set_int( mlt_producer_properties( title ), "x", 200 ); mlt_properties_set_int( mlt_producer_properties( title ), "y", 40 ); mlt_properties_set_double( mlt_producer_properties( title ), "mix", 0.8 ); // Register producers(s) with a multitrack object mlt_multitrack multitrack = mlt_multitrack_init( ); mlt_multitrack_connect( multitrack, mlt_playlist_producer( pl1 ), 0 ); mlt_multitrack_connect( multitrack, mlt_playlist_producer( pl2 ), 1 ); // Define a transition mlt_transition transition = mlt_factory_transition( "composite", NULL ); mlt_transition_connect( transition, mlt_multitrack_service( multitrack ), 0, 1 ); mlt_transition_set_in_and_out( transition, 0.0, 9999.0 ); // Buy a tractor and connect it to the filter mlt_tractor tractor = mlt_tractor_init( ); mlt_tractor_connect( tractor, mlt_transition_service( transition ) ); // Connect the tractor to the consumer mlt_consumer_connect( consumer, mlt_tractor_service( tractor ) ); // Do stuff until we're told otherwise... fprintf( stderr, "Press return to continue\n" ); fgets( temp, 132, stdin ); // Close everything... mlt_consumer_close( consumer ); mlt_tractor_close( tractor ); mlt_transition_close( transition ); mlt_multitrack_close( multitrack ); mlt_playlist_close( pl1 ); mlt_playlist_close( pl2 ); mlt_producer_close( dv1 ); mlt_producer_close( title ); return 0; }