static void mlt_producer_set_clones( mlt_producer self, int clones ) { mlt_producer parent = mlt_producer_cut_parent( self ); mlt_properties properties = MLT_PRODUCER_PROPERTIES( parent ); int existing = mlt_properties_get_int( properties, "_clones" ); int i = 0; char key[ 25 ]; // If the number of existing clones is different, then create/remove as necessary if ( existing != clones ) { if ( existing < clones ) { for ( i = existing; i < clones; i ++ ) { mlt_producer clone = mlt_producer_clone( parent ); sprintf( key, "_clone.%d", i ); mlt_properties_set_data( properties, key, clone, 0, ( mlt_destructor )mlt_producer_close, NULL ); } } else { for ( i = clones; i < existing; i ++ ) { sprintf( key, "_clone.%d", i ); mlt_properties_set_data( properties, key, NULL, 0, NULL, NULL ); } } } // Ensure all properties on the parent are passed to the clones for ( i = 0; i < clones; i ++ ) { mlt_producer clone = NULL; sprintf( key, "_clone.%d", i ); clone = mlt_properties_get_data( properties, key, NULL ); if ( clone != NULL ) mlt_properties_pass( MLT_PRODUCER_PROPERTIES( clone ), properties, "" ); } // Update the number of clones on the properties mlt_properties_set_int( properties, "_clones", clones ); }
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 consumer_start( mlt_consumer parent ) { consumer_sdl self = parent->child; if ( !self->running ) { // properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( parent ); mlt_properties play = MLT_CONSUMER_PROPERTIES( self->play ); mlt_properties still = MLT_CONSUMER_PROPERTIES( self->still ); char *window_id = mlt_properties_get( properties, "window_id" ); char *audio_driver = mlt_properties_get( properties, "audio_driver" ); char *video_driver = mlt_properties_get( properties, "video_driver" ); char *audio_device = mlt_properties_get( properties, "audio_device" ); char *output_display = mlt_properties_get( properties, "output_display" ); int progressive = mlt_properties_get_int( properties, "progressive" ) | mlt_properties_get_int( properties, "deinterlace" ); consumer_stop( parent ); self->running = 1; self->joined = 0; self->last_speed = 1; if ( output_display != NULL ) setenv( "DISPLAY", output_display, 1 ); if ( window_id != NULL ) setenv( "SDL_WINDOWID", window_id, 1 ); if ( video_driver != NULL ) setenv( "SDL_VIDEODRIVER", video_driver, 1 ); if ( audio_driver != NULL ) setenv( "SDL_AUDIODRIVER", audio_driver, 1 ); if ( audio_device != NULL ) setenv( "AUDIODEV", audio_device, 1 ); pthread_mutex_lock( &mlt_sdl_mutex ); int ret = SDL_Init( SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE ); pthread_mutex_unlock( &mlt_sdl_mutex ); if ( ret < 0 ) { fprintf( stderr, "Failed to initialize SDL: %s\n", SDL_GetError() ); return -1; } SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL ); SDL_EnableUNICODE( 1 ); // Pass properties down mlt_properties_set_data( play, "transport_producer", mlt_properties_get_data( properties, "transport_producer", NULL ), 0, NULL, NULL ); mlt_properties_set_data( still, "transport_producer", mlt_properties_get_data( properties, "transport_producer", NULL ), 0, NULL, NULL ); mlt_properties_set_data( play, "transport_callback", mlt_properties_get_data( properties, "transport_callback", NULL ), 0, NULL, NULL ); mlt_properties_set_data( still, "transport_callback", mlt_properties_get_data( properties, "transport_callback", NULL ), 0, NULL, NULL ); mlt_properties_set_int( play, "progressive", progressive ); mlt_properties_set_int( still, "progressive", progressive ); mlt_properties_pass_list( play, properties, "deinterlace_method,resize,rescale,width,height,aspect_ratio,display_ratio,preview_off,preview_format,window_background" ",top_field_first,volume,real_time,buffer,prefill,audio_off,frequency,drop_max" ); mlt_properties_pass_list( still, properties, "deinterlace_method,resize,rescale,width,height,aspect_ratio,display_ratio,preview_off,preview_format,window_background" ",top_field_first"); mlt_properties_pass( play, properties, "play." ); mlt_properties_pass( still, properties, "still." ); mlt_properties_set_data( play, "app_lock", mlt_properties_get_data( properties, "app_lock", NULL ), 0, NULL, NULL ); mlt_properties_set_data( still, "app_lock", mlt_properties_get_data( properties, "app_lock", NULL ), 0, NULL, NULL ); mlt_properties_set_data( play, "app_unlock", mlt_properties_get_data( properties, "app_unlock", NULL ), 0, NULL, NULL ); mlt_properties_set_data( still, "app_unlock", mlt_properties_get_data( properties, "app_unlock", NULL ), 0, NULL, NULL ); mlt_properties_set_int( play, "put_mode", 1 ); mlt_properties_set_int( still, "put_mode", 1 ); mlt_properties_set_int( play, "terminate_on_pause", 1 ); // Start the still producer just to initialise the gui mlt_consumer_start( self->still ); self->active = self->still; // Inform child consumers that we control the sdl mlt_properties_set_int( play, "sdl_started", 1 ); mlt_properties_set_int( still, "sdl_started", 1 ); pthread_create( &self->thread, NULL, consumer_thread, 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 create_instance( mlt_transition transition, char *name, char *value, int count ) { // Return from this function int error = 0; // Duplicate the value char *type = strdup( value ); // Pointer to filter argument char *arg = type == NULL ? NULL : strchr( type, ':' ); // New filter being created mlt_filter filter = NULL; // Cleanup type and arg if ( arg != NULL ) *arg ++ = '\0'; // Create the filter mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( transition ) ); if ( type ) filter = mlt_factory_filter( profile, type, arg ); // If we have a filter, then initialise and store it if ( filter != NULL ) { // Properties of transition mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition ); // String to hold the property name char id[ 256 ]; // String to hold the passdown key char key[ 256 ]; // Construct id sprintf( id, "_filter_%d", count ); // Counstruct key sprintf( key, "%s.", name ); // Just in case, let's assume that the filter here has a composite //mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "composite.geometry", "0%/0%:100%x100%" ); //mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "composite.fill", 1 ); // Pass all the key properties on the filter down mlt_properties_pass( MLT_FILTER_PROPERTIES( filter ), properties, key ); mlt_properties_pass_list( MLT_FILTER_PROPERTIES( filter ), properties, "in, out, length" ); // Ensure that filter is assigned mlt_properties_set_data( properties, id, filter, 0, ( mlt_destructor )mlt_filter_close, NULL ); } else { // Indicate that an error has occurred error = 1; } // Cleanup free( type ); // Return error condition 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; }
bool ServiceManager::initialize(int width, int height) { if (effects) return true; mlt_properties properties = MLT_SERVICE_PROPERTIES(service); // Create and initialize Effects const char* fileName = mlt_properties_get(properties, "resource"); if (!fileName) { mlt_log(service, MLT_LOG_ERROR, "No 'resource' property found\n"); return false; } bool isTransparent = mlt_properties_get_int(properties, "transparent") || mlt_service_identify(service) == filter_type; parameters = new ServiceParameters(service); effects = WebVfx::createEffects(fileName, width, height, parameters, isTransparent); if (!effects) { mlt_log(service, MLT_LOG_ERROR, "Failed to create WebVfx Effects for resource %s\n", fileName); return false; } // Iterate over image map - save source and target image names, // and create an ImageProducer for each extra image. char* factory = mlt_properties_get(properties, "factory"); WebVfx::Effects::ImageTypeMapIterator it(effects->getImageTypeMap()); while (it.hasNext()) { it.next(); const QString& imageName = it.key(); switch (it.value()) { case WebVfx::Effects::SourceImageType: sourceImageName = imageName; break; case WebVfx::Effects::TargetImageType: targetImageName = imageName; break; case WebVfx::Effects::ExtraImageType: { if (!imageProducers) imageProducers = new std::vector<ImageProducer*>(3); // Property prefix "producer.<name>." QString producerPrefix("producer."); producerPrefix.append(imageName).append("."); // Find producer.<name>.resource property QString resourceName(producerPrefix); resourceName.append("resource"); char* resource = mlt_properties_get(properties, resourceName.toLatin1().constData()); if (resource) { mlt_producer producer = mlt_factory_producer(mlt_service_profile(service), factory, resource); if (!producer) { mlt_log(service, MLT_LOG_ERROR, "WebVfx failed to create extra image producer for %s\n", resourceName.toLatin1().constData()); return false; } // Copy producer.<name>.* properties onto producer mlt_properties_pass(MLT_PRODUCER_PROPERTIES(producer), properties, producerPrefix.toLatin1().constData()); // Append ImageProducer to vector imageProducers->insert(imageProducers->end(), new ImageProducer(imageName, producer)); } else mlt_log(service, MLT_LOG_WARNING, "WebVfx no producer resource property specified for extra image %s\n", resourceName.toLatin1().constData()); break; } default: mlt_log(service, MLT_LOG_ERROR, "Invalid WebVfx image type %d\n", it.value()); break; } } return true; }
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 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" ); mlt_properties_pass( MLT_CONSUMER_PROPERTIES( cx->consumer ), properties, CONSUMER_PROPERTIES_PREFIX ); mlt_properties_pass( MLT_PRODUCER_PROPERTIES( cx->producer ), properties, PRODUCER_PROPERTIES_PREFIX ); mlt_events_listen( properties, self, "property-changed", ( mlt_listener )property_changed ); // 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; }