static int get_image_b( mlt_frame b_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_transition self = mlt_frame_pop_service( b_frame ); mlt_frame a_frame = mlt_frame_pop_frame( b_frame ); mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame ); mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame ); // Set scaling from A frame if not already provided. if ( !mlt_properties_get( b_props, "rescale.interp" ) ) { const char *rescale = mlt_properties_get( a_props, "rescale.interp" ); if ( !rescale || !strcmp( rescale, "none" ) ) rescale = "nearest"; mlt_properties_set( b_props, "rescale.interp", rescale ); } // Ensure sane aspect ratio if ( mlt_frame_get_aspect_ratio( b_frame ) == 0.0 ) mlt_frame_set_aspect_ratio( b_frame, mlt_profile_sar( mlt_service_profile( MLT_TRANSITION_SERVICE(self) ) ) ); mlt_properties_pass_list( b_props, a_props, "consumer_deinterlace, deinterlace_method, consumer_tff" ); return mlt_frame_get_image( b_frame, image, format, width, height, writable ); }
static int get_image_a( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_transition self = mlt_frame_pop_service( a_frame ); mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame ); // All transitions get scaling const char *rescale = mlt_properties_get( a_props, "rescale.interp" ); if ( !rescale || !strcmp( rescale, "none" ) ) mlt_properties_set( a_props, "rescale.interp", "nearest" ); // Ensure sane aspect ratio if ( mlt_frame_get_aspect_ratio( a_frame ) == 0.0 ) mlt_frame_set_aspect_ratio( a_frame, mlt_profile_sar( mlt_service_profile( MLT_TRANSITION_SERVICE(self) ) ) ); return mlt_frame_get_image( a_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; }
static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { int error = 0; // Get the properties from the frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); // Pop the top of stack now mlt_filter filter = mlt_frame_pop_service( frame ); mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); // Retrieve the aspect ratio double aspect_ratio = mlt_deque_pop_back_double( MLT_FRAME_IMAGE_STACK( frame ) ); double consumer_aspect = mlt_profile_sar( mlt_service_profile( MLT_FILTER_SERVICE( filter ) ) ); // Correct Width/height if necessary if ( *width == 0 || *height == 0 ) { *width = profile->width; *height = profile->height; } // Assign requested width/height from our subordinate int owidth = *width; int oheight = *height; // Check for the special case - no aspect ratio means no problem :-) if ( aspect_ratio == 0.0 ) aspect_ratio = consumer_aspect; // Reset the aspect ratio mlt_properties_set_double( properties, "aspect_ratio", aspect_ratio ); // XXX: This is a hack, but it forces the force_full_luma to apply by doing a RGB // conversion because range scaling only occurs on YUV->RGB. And we do it here, // after the deinterlace filter, which only operates in YUV to avoid a YUV->RGB->YUV->?. // Instead, it will go YUV->RGB->?. if ( mlt_properties_get_int( properties, "force_full_luma" ) ) *format = mlt_image_rgb24a; // Hmmm... char *rescale = mlt_properties_get( properties, "rescale.interp" ); if ( rescale != NULL && !strcmp( rescale, "none" ) ) return mlt_frame_get_image( frame, image, format, width, height, writable ); if ( mlt_properties_get_int( properties, "distort" ) == 0 ) { // Normalise the input and out display aspect int normalised_width = profile->width; int normalised_height = profile->height; int real_width = mlt_properties_get_int( properties, "meta.media.width" ); int real_height = mlt_properties_get_int( properties, "meta.media.height" ); if ( real_width == 0 ) real_width = mlt_properties_get_int( properties, "width" ); if ( real_height == 0 ) real_height = mlt_properties_get_int( properties, "height" ); double input_ar = aspect_ratio * real_width / real_height; double output_ar = consumer_aspect * owidth / oheight; // fprintf( stderr, "real %dx%d normalised %dx%d output %dx%d sar %f in-dar %f out-dar %f\n", // real_width, real_height, normalised_width, normalised_height, owidth, oheight, aspect_ratio, input_ar, output_ar); // Optimised for the input_ar > output_ar case (e.g. widescreen on standard) int scaled_width = rint( ( input_ar * normalised_width ) / output_ar ); int scaled_height = normalised_height; // Now ensure that our images fit in the output frame if ( scaled_width > normalised_width ) { scaled_width = normalised_width; scaled_height = rint( ( output_ar * normalised_height ) / input_ar ); } // Now calculate the actual image size that we want owidth = rint( scaled_width * owidth / normalised_width ); oheight = rint( scaled_height * oheight / normalised_height ); // Tell frame we have conformed the aspect to the consumer mlt_frame_set_aspect_ratio( frame, consumer_aspect ); } mlt_properties_set_int( properties, "distort", 0 ); // Now pass on the calculations down the line mlt_properties_set_int( properties, "resize_width", *width ); mlt_properties_set_int( properties, "resize_height", *height ); // If there will be padding, then we need packed image format. if ( *format == mlt_image_yuv420p ) { int iwidth = mlt_properties_get_int( properties, "width" ); int iheight = mlt_properties_get_int( properties, "height" ); if ( iwidth < owidth || iheight < oheight ) *format = mlt_image_yuv422; } // Now get the image if ( *format == mlt_image_yuv422 ) owidth -= owidth % 2; error = mlt_frame_get_image( frame, image, format, &owidth, &oheight, writable ); if ( error == 0 && *image ) { int bpp; mlt_image_format_size( *format, owidth, oheight, &bpp ); *image = frame_resize_image( frame, *width, *height, bpp ); } 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; }