static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { context cx = mlt_frame_pop_service( frame ); mlt_frame nested_frame = mlt_frame_pop_service( frame ); *width = cx->profile->width; *height = cx->profile->height; int result = mlt_frame_get_image( nested_frame, image, format, width, height, writable ); // Allocate the image int size = mlt_image_format_size( *format, *width, *height, NULL ); uint8_t *new_image = mlt_pool_alloc( size ); // Update the frame mlt_properties properties = mlt_frame_properties( frame ); mlt_frame_set_image( frame, new_image, size, mlt_pool_release ); memcpy( new_image, *image, size ); mlt_properties_set( properties, "progressive", mlt_properties_get( MLT_FRAME_PROPERTIES(nested_frame), "progressive" ) ); *image = new_image; // Copy the alpha channel uint8_t *alpha = mlt_properties_get_data( MLT_FRAME_PROPERTIES( nested_frame ), "alpha", &size ); if ( alpha && size > 0 ) { new_image = mlt_pool_alloc( size ); memcpy( new_image, alpha, size ); mlt_frame_set_alpha( frame, new_image, size, mlt_pool_release ); } return result; }
static int producer_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the producer service mlt_producer producer = mlt_properties_get_data( MLT_FRAME_PROPERTIES( frame ), "_producer_ladspa", NULL ); mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); int size = 0; LADSPA_Data** output_buffers = NULL; int i = 0; // Initialize LADSPA if needed jack_rack_t *jackrack = mlt_properties_get_data( producer_properties, "_jackrack", NULL ); if ( !jackrack ) { sample_rate = *frequency; // global inside jack_rack jackrack = initialise_jack_rack( producer_properties, *channels ); } if( jackrack ) { // Correct the returns if necessary *samples = *samples <= 0 ? 1920 : *samples; *channels = *channels <= 0 ? 2 : *channels; *frequency = *frequency <= 0 ? 48000 : *frequency; *format = mlt_audio_float; // Calculate the size of the buffer size = *samples * *channels * sizeof( float ); // Allocate the buffer *buffer = mlt_pool_alloc( size ); // Initialize the LADSPA output buffer. output_buffers = mlt_pool_alloc( sizeof( LADSPA_Data* ) * *channels ); for ( i = 0; i < *channels; i++ ) { output_buffers[i] = (LADSPA_Data*) *buffer + i * *samples; } // Do LADSPA processing process_ladspa( jackrack->procinfo, *samples, NULL, output_buffers ); mlt_pool_release( output_buffers ); // Set the buffer for destruction mlt_frame_set_audio( frame, *buffer, *format, size, mlt_pool_release ); } return 0; }
static int iconv_from_utf8( mlt_properties properties, const char *prop_name, const char *prop_name_out, const char* encoding ) { const char *text = mlt_properties_get( properties, prop_name ); int result = -1; iconv_t cd = iconv_open( encoding, "UTF-8" ); if ( text && ( cd != ( iconv_t )-1 ) ) { size_t inbuf_n = strlen( text ); size_t outbuf_n = inbuf_n * 6; char *outbuf = mlt_pool_alloc( outbuf_n ); char *outbuf_p = outbuf; memset( outbuf, 0, outbuf_n ); if ( text != NULL && strcmp( text, "" ) && iconv( cd, &text, &inbuf_n, &outbuf_p, &outbuf_n ) != -1 ) mlt_properties_set( properties, prop_name_out, outbuf ); else mlt_properties_set( properties, prop_name_out, "" ); mlt_pool_release( outbuf ); result = 0; } iconv_close( cd ); return result; }
mlt_filter filter_avresample_init( char *arg ) { // Create a filter mlt_filter filter = mlt_filter_new( ); // Initialise if successful if ( filter != NULL ) { // Calculate size of the buffer int size = MAX_AUDIO_FRAME_SIZE * sizeof( int16_t ); // Allocate the buffer int16_t *buffer = mlt_pool_alloc( size ); // Assign the process method filter->process = filter_process; // Deal with argument if ( arg != NULL ) mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "frequency", arg ); // Default to 2 channel output mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "channels", 2 ); // Store the buffer mlt_properties_set_data( MLT_FILTER_PROPERTIES( filter ), "buffer", buffer, size, mlt_pool_release, NULL ); } return filter; }
static int get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { mlt_frame nested_frame = mlt_frame_pop_audio( frame ); int result = mlt_frame_get_audio( nested_frame, buffer, format, frequency, channels, samples ); int size = *channels * *samples; switch ( *format ) { case mlt_audio_s16: size *= sizeof( int16_t ); break; case mlt_audio_s32: size *= sizeof( int32_t ); case mlt_audio_float: size *= sizeof( float ); default: mlt_log_error( NULL, "[producer consumer] Invalid audio format\n" ); } int16_t *new_buffer = mlt_pool_alloc( size ); mlt_properties_set_data( MLT_FRAME_PROPERTIES( frame ), "audio", new_buffer, size, mlt_pool_release, NULL ); memcpy( new_buffer, *buffer, size ); *buffer = new_buffer; return result; }
static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { // Obtain properties of frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); // Obtain the producer for this frame mlt_producer producer = mlt_properties_get_data( properties, "producer_frei0r", NULL ); // Obtain properties of producer mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer ); // Allocate the image int size = *width * ( *height + 1 ) * 2; // Allocate the image *buffer = mlt_pool_alloc( size ); // Update the frame mlt_properties_set_data( properties, "image", *buffer, size, mlt_pool_release, NULL ); mlt_properties_set_int( properties, "width", *width ); mlt_properties_set_int( properties, "height", *height ); *format = mlt_image_yuv422; if ( *buffer != NULL ) { mlt_position in = mlt_producer_get_in( producer ); mlt_position out = mlt_producer_get_out( producer ); mlt_position time = mlt_frame_get_position( frame ); double position = ( double )( time - in ) / ( double )( out - in + 1 ); process_frei0r_item( producer_type , position, producer_props, frame , buffer, format , width , height , writable ); } return 0; }
static int attach_boundry_to_frame( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the filter object mlt_filter filter = mlt_frame_pop_service( frame ); // Get the filter's property object mlt_properties filter_properties = MLT_FILTER_PROPERTIES(filter); // Get the frame properties mlt_properties frame_properties = MLT_FRAME_PROPERTIES(frame); // Get the frame position mlt_position position = mlt_filter_get_position( filter, frame ); mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); // Get the geometry object mlt_geometry geometry = mlt_properties_get_data(filter_properties, "filter_geometry", NULL); if (geometry == NULL) { mlt_geometry geom = mlt_geometry_init(); char *arg = mlt_properties_get(filter_properties, "geometry"); // Initialize with the supplied geometry struct mlt_geometry_item_s item; mlt_geometry_parse_item( geom, &item, arg ); item.frame = 0; item.key = 1; item.mix = 100; mlt_geometry_insert( geom, &item ); mlt_geometry_interpolate( geom ); mlt_properties_set_data( filter_properties, "filter_geometry", geom, 0, (mlt_destructor)mlt_geometry_close, (mlt_serialiser)mlt_geometry_serialise ); geometry = mlt_properties_get_data(filter_properties, "filter_geometry", NULL); } mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); // Get the current geometry item mlt_geometry_item geometry_item = mlt_pool_alloc( sizeof( struct mlt_geometry_item_s ) ); mlt_geometry_fetch(geometry, geometry_item, position); // Cleanse the geometry item geometry_item->w = geometry_item->x < 0 ? geometry_item->w + geometry_item->x : geometry_item->w; geometry_item->h = geometry_item->y < 0 ? geometry_item->h + geometry_item->y : geometry_item->h; geometry_item->x = geometry_item->x < 0 ? 0 : geometry_item->x; geometry_item->y = geometry_item->y < 0 ? 0 : geometry_item->y; geometry_item->w = geometry_item->w < 0 ? 0 : geometry_item->w; geometry_item->h = geometry_item->h < 0 ? 0 : geometry_item->h; mlt_properties_set_data( frame_properties, "bounds", geometry_item, sizeof( struct mlt_geometry_item_s ), mlt_pool_release, NULL ); // Get the new image int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); if( error != 0 ) mlt_properties_debug( frame_properties, "error after mlt_frame_get_image() in autotrack_rectangle attach_boundry_to_frame", stderr ); return error; }
static int get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { context cx = mlt_frame_pop_audio( frame ); mlt_frame nested_frame = mlt_frame_pop_audio( frame ); int result = 0; // if not repeating last frame if ( mlt_frame_get_position( nested_frame ) != cx->audio_position ) { double fps = mlt_profile_fps( cx->profile ); if ( mlt_producer_get_fps( cx->self ) < fps ) fps = mlt_producer_get_fps( cx->self ); *samples = mlt_sample_calculator( fps, *frequency, cx->audio_counter++ ); result = mlt_frame_get_audio( nested_frame, buffer, format, frequency, channels, samples ); int size = mlt_audio_format_size( *format, *samples, *channels ); int16_t *new_buffer = mlt_pool_alloc( size ); mlt_frame_set_audio( frame, new_buffer, *format, size, mlt_pool_release ); memcpy( new_buffer, *buffer, size ); *buffer = new_buffer; cx->audio_position = mlt_frame_get_position( nested_frame ); } else { // otherwise return no samples *samples = 0; *buffer = NULL; } return result; }
static uint8_t *resize_alpha( uint8_t *input, int owidth, int oheight, int iwidth, int iheight, uint8_t alpha_value ) { uint8_t *output = NULL; if ( input != NULL && ( iwidth != owidth || iheight != oheight ) && ( owidth > 6 && oheight > 6 ) ) { uint8_t *out_line; int offset_x = ( owidth - iwidth ) / 2; int offset_y = ( oheight - iheight ) / 2; int iused = iwidth; output = mlt_pool_alloc( owidth * oheight ); memset( output, alpha_value, owidth * oheight ); offset_x -= offset_x % 2; out_line = output + offset_y * owidth; out_line += offset_x; // Loop for the entirety of our output height. while ( iheight -- ) { // We're in the input range for this row. memcpy( out_line, input, iused ); // Move to next input line input += iwidth; // Move to next output line out_line += owidth; } } return output; }
static uint8_t *filter_get_alpha_mask( mlt_frame frame ) { uint8_t *alpha = NULL; // Obtain properties of frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); // Get the shape frame mlt_frame shape_frame = mlt_properties_get_data( properties, "shape_frame", NULL ); // Get the width and height of the image int region_width = mlt_properties_get_int( properties, "width" ); int region_height = mlt_properties_get_int( properties, "height" ); uint8_t *image = NULL; mlt_image_format format = mlt_image_yuv422; // Get the shape image to trigger alpha creation mlt_properties_set_int( MLT_FRAME_PROPERTIES( shape_frame ), "distort", 1 ); mlt_frame_get_image( shape_frame, &image, &format, ®ion_width, ®ion_height, 0 ); alpha = mlt_frame_get_alpha_mask( shape_frame ); int size = region_width * region_height; uint8_t *alpha_duplicate = mlt_pool_alloc( size ); int holewhite = mlt_properties_get_int(properties,"holecolor"); if (holewhite) { alpha = alpha_duplicate; while (size--) { uint8_t test = ( int )( ( ( *image ++ - 16 ) * 299 ) / 255 ); if (test <= 10) { *alpha = holewhite==1?0:255; } else if (test >= 250 ) { *alpha = holewhite==2?0:255; } alpha++; image++; } } // Generate from the Y component of the image if no alpha available else if ( alpha == NULL ) { alpha = alpha_duplicate; while ( size -- ) { *alpha ++ = ( int )( ( ( *image ++ - 16 ) * 299 ) / 255 ); image ++; } } else { memcpy( alpha_duplicate, alpha, size ); } mlt_frame_set_alpha( frame, alpha_duplicate, region_width * region_height, mlt_pool_release ); return alpha_duplicate; }
static void draw_spectrum( mlt_filter filter, mlt_frame frame, QImage* qimg ) { mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); mlt_position position = mlt_filter_get_position( filter, frame ); mlt_position length = mlt_filter_get_length2( filter, frame ); mlt_rect rect = mlt_properties_anim_get_rect( filter_properties, "rect", position, length ); if ( strchr( mlt_properties_get( filter_properties, "rect" ), '%' ) ) { rect.x *= qimg->width(); rect.w *= qimg->width(); rect.y *= qimg->height(); rect.h *= qimg->height(); } char* graph_type = mlt_properties_get( filter_properties, "type" ); int mirror = mlt_properties_get_int( filter_properties, "mirror" ); int fill = mlt_properties_get_int( filter_properties, "fill" ); double tension = mlt_properties_get_double( filter_properties, "tension" ); QRectF r( rect.x, rect.y, rect.w, rect.h ); QPainter p( qimg ); if( mirror ) { // Draw two half rectangle instead of one full rectangle. r.setHeight( r.height() / 2.0 ); } setup_graph_painter( p, r, filter_properties ); setup_graph_pen( p, r, filter_properties ); int bands = mlt_properties_get_int( filter_properties, "bands" ); if ( bands == 0 ) { // "0" means match rectangle width bands = r.width(); } float* spectrum = (float*)mlt_pool_alloc( bands * sizeof(float) ); convert_fft_to_spectrum( filter, frame, bands, spectrum ); if( graph_type && graph_type[0] == 'b' ) { paint_bar_graph( p, r, bands, spectrum ); } else { paint_line_graph( p, r, bands, spectrum, tension, fill ); } if( mirror ) { // Second rectangle is mirrored. p.translate( 0, r.y() * 2 + r.height() * 2 ); p.scale( 1, -1 ); if( graph_type && graph_type[0] == 'b' ) { paint_bar_graph( p, r, bands, spectrum ); } else { paint_line_graph( p, r, bands, spectrum, tension, fill ); } } mlt_pool_release( spectrum ); p.end(); }
static int producerGetImage(mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int /*writable*/) { int error = 0; mlt_properties properties = MLT_FRAME_PROPERTIES(frame); mlt_producer producer = (mlt_producer)mlt_properties_get_data(properties, kWebVfxProducerPropertyName, NULL); mlt_properties producer_props = MLT_PRODUCER_PROPERTIES(producer); int size; int bpp; bool hasTransparency = false; { MLTWebVfx::ServiceLocker locker(MLT_PRODUCER_SERVICE(producer)); if (!locker.initialize(*width, *height)) return 1; if (mlt_properties_get_int( producer_props, "transparent") ) { *format = mlt_image_rgb24a; hasTransparency = true; } else { *format = mlt_image_rgb24; } // Get bpp from image format mlt_image_format_size(*format, 0, 0, &bpp); size = *width * *height * bpp; *buffer = (uint8_t*)mlt_pool_alloc(size); // When not using transparency, this will make the background black... memset( *buffer, 255, size ); WebVfx::Image outputImage(*buffer, *width, *height, size, hasTransparency); locker.getManager()->render(&outputImage, mlt_properties_get_position(properties, kWebVfxPositionPropertyName), mlt_producer_get_length(producer), hasTransparency); } mlt_frame_set_image(frame, *buffer, size, mlt_pool_release); if (hasTransparency) { // Create the alpha channel int alpha_size = *width * *height; uint8_t *alpha = (uint8_t *)mlt_pool_alloc( alpha_size ); // Initialise the alpha memset( alpha, 255, alpha_size ); mlt_frame_set_alpha(frame, alpha, alpha_size, mlt_pool_release); } return error; }
static int producer_get_image( mlt_frame frame, uint8_t** buffer, mlt_image_format* format, int* width, int* height, int writable ) { mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); mlt_producer producer = static_cast<mlt_producer>( mlt_properties_get_data( frame_properties, "_producer_qtext", NULL ) ); mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); int img_size = 0; int alpha_size = 0; uint8_t* alpha = NULL; QImage* qImg = static_cast<QImage*>( mlt_properties_get_data( producer_properties, "_qimg", NULL ) ); mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) ); // Regenerate the qimage if necessary if( check_qimage( frame_properties ) == true ) { generate_qimage( frame_properties ); } *format = mlt_image_rgb24a; *width = qImg->width(); *height = qImg->height(); // Allocate and fill the image buffer img_size = mlt_image_format_size( *format, *width, *height, NULL ); *buffer = static_cast<uint8_t*>( mlt_pool_alloc( img_size ) ); copy_qimage_to_mlt_image( qImg, *buffer ); mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); // Allocate and fill the alpha buffer alpha_size = *width * *height; alpha = static_cast<uint8_t*>( mlt_pool_alloc( alpha_size ) ); copy_image_to_alpha( *buffer, alpha, *width, *height ); // Update the frame mlt_frame_set_image( frame, *buffer, img_size, mlt_pool_release ); mlt_frame_set_alpha( frame, alpha, alpha_size, mlt_pool_release ); mlt_properties_set_int( frame_properties, "width", *width ); mlt_properties_set_int( frame_properties, "height", *height ); return 0; }
static int filter_get_audio( mlt_frame frame, void** buffer, mlt_audio_format* format, int* frequency, int* channels, int* samples ) { mlt_filter filter = (mlt_filter)mlt_frame_pop_audio( frame ); mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); private_data* pdata = (private_data*)filter->child; // Create the FFT filter the first time. if( !pdata->fft ) { mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE(filter) ); pdata->fft = mlt_factory_filter( profile, "fft", NULL ); mlt_properties_set_int( MLT_FILTER_PROPERTIES( pdata->fft ), "window_size", mlt_properties_get_int( filter_properties, "window_size" ) ); if( !pdata->fft ) { mlt_log_warning( MLT_FILTER_SERVICE(filter), "Unable to create FFT.\n" ); return 1; } } mlt_properties fft_properties = MLT_FILTER_PROPERTIES( pdata->fft ); // The service must stay locked while using the private data mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); // Perform FFT processing on the frame mlt_filter_process( pdata->fft, frame ); mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); float* bins = (float*)mlt_properties_get_data( fft_properties, "bins", NULL ); if( bins ) { double window_level = mlt_properties_get_double( fft_properties, "window_level" ); int bin_count = mlt_properties_get_int( fft_properties, "bin_count" ); size_t bins_size = bin_count * sizeof(float); float* save_bins = (float*)mlt_pool_alloc( bins_size ); if( window_level == 1.0 ) { memcpy( save_bins, bins, bins_size ); } else { memset( save_bins, 0, bins_size ); } // Save the bin data as a property on the frame to be used in get_image() mlt_properties_set_data( MLT_FRAME_PROPERTIES(frame), pdata->fft_prop_name, save_bins, bins_size, mlt_pool_release, NULL ); } mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); return 0; }
static int ladspa_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the filter service mlt_filter filter = mlt_frame_pop_audio( frame ); // Get the filter properties mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); // Get the producer's audio *format = mlt_audio_float; mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); // Initialise LADSPA if needed jack_rack_t *jackrack = mlt_properties_get_data( filter_properties, "jackrack", NULL ); if ( jackrack == NULL ) { sample_rate = *frequency; // global inside jack_rack jackrack = initialise_jack_rack( filter_properties, *channels ); } // Get the filter-specific properties LADSPA_Data **input_buffers = mlt_pool_alloc( sizeof( LADSPA_Data* ) * *channels ); LADSPA_Data **output_buffers = mlt_pool_alloc( sizeof( LADSPA_Data* ) * *channels ); int i; for ( i = 0; i < *channels; i++ ) { input_buffers[i] = (LADSPA_Data*) *buffer + i * *samples; output_buffers[i] = (LADSPA_Data*) *buffer + i * *samples; } // Do LADSPA processing int error = jackrack && process_ladspa( jackrack->procinfo, *samples, input_buffers, output_buffers ); mlt_pool_release( input_buffers ); mlt_pool_release( output_buffers ); return error; }
static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { /* Obtain properties of frame */ mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); /* Obtain the producer for this frame */ producer_ktitle this = mlt_properties_get_data( properties, "producer_kdenlivetitle", NULL ); /* Obtain properties of producer */ mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( &this->parent ); *width = mlt_properties_get_int( properties, "rescale_width" ); *height = mlt_properties_get_int( properties, "rescale_height" ); /* Allocate the image */ int size = *width * ( *height ) * 4; /* Allocate the image */ *format = mlt_image_rgb24a; mlt_position time = mlt_producer_position( &this->parent ) + mlt_producer_get_in( &this->parent ); if ( mlt_properties_get_int( producer_props, "force_reload" ) ) { if (mlt_properties_get_int( producer_props, "force_reload" ) > 1) read_xml(producer_props); mlt_properties_set_int( producer_props, "force_reload", 0 ); drawKdenliveTitle( this, frame, *width, *height, time, 1); } else drawKdenliveTitle( this, frame, *width, *height, time, 0); // Get width and height (may have changed during the refresh) *width = mlt_properties_get_int( properties, "width" ); *height = mlt_properties_get_int( properties, "height" ); if ( this->current_image ) { // Clone the image and the alpha int image_size = this->current_width * ( this->current_height ) * 4; uint8_t *image_copy = mlt_pool_alloc( image_size ); memcpy( image_copy, this->current_image, image_size ); // Now update properties so we free the copy after mlt_properties_set_data( properties, "image", image_copy, image_size, mlt_pool_release, NULL ); // We're going to pass the copy on *buffer = image_copy; /* Update the frame */ mlt_properties_set_data( properties, "image", *buffer, size, mlt_pool_release, NULL ); mlt_log_debug( MLT_PRODUCER_SERVICE( &this->parent ), "width:%d height:%d %s\n", *width, *height, mlt_image_format_name( *format ) ); } return 0; }
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 position = mlt_frame_get_position( frame ); // Get the image *format = mlt_image_yuv422; int error = mlt_frame_get_image( frame, image, format, width, height, 0 ); // Only process if we have no error and a valid colour space if ( error == 0 ) { double factor = mlt_properties_get_double( properties, "start" ); mlt_position f_pos = mlt_filter_get_position( filter, frame ); mlt_position f_len = mlt_filter_get_length2( filter, frame ); int speed = mlt_properties_anim_get_int( properties, "speed", f_pos, f_len ); int deformX = mlt_properties_anim_get_int( properties, "deformX", f_pos, f_len ); int deformY = mlt_properties_anim_get_int( properties, "deformY", f_pos, f_len ); if ( mlt_properties_get( properties, "end" ) ) { // Determine the time position of this frame in the transition duration double end = fabs( mlt_properties_get_double( MLT_FILTER_PROPERTIES( filter ), "end" ) ); factor += ( end - factor ) * mlt_filter_get_progress( filter, frame ); } // If animated property "wave" is set, use its value. char* wave_property = mlt_properties_get( properties, "wave" ); if ( wave_property ) { factor = mlt_properties_anim_get_double( properties, "wave", f_pos, f_len ); } if (factor != 0) { int image_size = *width * (*height) * 2; uint8_t *dst = mlt_pool_alloc (image_size); DoWave(*image, *width, (*height), dst, position, speed, factor, deformX, deformY); *image = dst; mlt_frame_set_image( frame, *image, image_size, mlt_pool_release ); } } return error; }
uint8_t *mlt_frame_get_alpha_mask( mlt_frame self ) { uint8_t *alpha = NULL; if ( self != NULL ) { if ( self->get_alpha_mask != NULL ) alpha = self->get_alpha_mask( self ); if ( alpha == NULL ) alpha = mlt_properties_get_data( &self->parent, "alpha", NULL ); if ( alpha == NULL ) { int size = mlt_properties_get_int( &self->parent, "width" ) * mlt_properties_get_int( &self->parent, "height" ); alpha = mlt_pool_alloc( size ); memset( alpha, 255, size ); mlt_properties_set_data( &self->parent, "alpha", alpha, size, mlt_pool_release, NULL ); } } return alpha; }
static uint8_t *frame_resize_image( mlt_frame frame, int owidth, int oheight, int bpp ) { // Get properties mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); // Get the input image, width and height uint8_t *input = mlt_properties_get_data( properties, "image", NULL ); uint8_t *alpha = mlt_frame_get_alpha( frame ); int alpha_size = 0; mlt_properties_get_data( properties, "alpha", &alpha_size ); int iwidth = mlt_properties_get_int( properties, "width" ); int iheight = mlt_properties_get_int( properties, "height" ); // If width and height are correct, don't do anything if ( iwidth < owidth || iheight < oheight ) { uint8_t alpha_value = mlt_properties_get_int( properties, "resize_alpha" ); // Create the output image uint8_t *output = mlt_pool_alloc( owidth * ( oheight + 1 ) * bpp ); // Call the generic resize resize_image( output, owidth, oheight, input, iwidth, iheight, bpp ); // Now update the frame mlt_frame_set_image( frame, output, owidth * ( oheight + 1 ) * bpp, mlt_pool_release ); // We should resize the alpha too if ( alpha && alpha_size >= iwidth * iheight ) { alpha = resize_alpha( alpha, owidth, oheight, iwidth, iheight, alpha_value ); if ( alpha ) mlt_frame_set_alpha( frame, alpha, owidth * oheight, mlt_pool_release ); } // Return the output return output; } // No change, return input return input; }
void read_xml(mlt_properties properties) { FILE *f = fopen( mlt_properties_get( properties, "resource" ), "r"); if ( f != NULL ) { int size = 0; long lSize; fseek (f , 0 , SEEK_END); lSize = ftell (f); rewind (f); char *infile = (char*) mlt_pool_alloc(lSize); size=fread(infile,1,lSize,f); infile[size] = '\0'; fclose(f); mlt_properties_set(properties, "_xmldata", infile); mlt_pool_release( infile ); } }
static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { producer_kino this = producer->child; uint8_t *data = mlt_pool_alloc( FRAME_SIZE_625_50 ); // Obtain the current frame number uint64_t position = mlt_producer_frame( producer ); // Create an empty frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); // Seek and fetch if ( kino_wrapper_get_frame( this->wrapper, data, position ) ) { // Get the frames properties mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); // Determine if we're PAL or NTSC int is_pal = kino_wrapper_is_pal( this->wrapper ); // Pass the dv data mlt_properties_set_data( properties, "dv_data", data, FRAME_SIZE_625_50, ( mlt_destructor )mlt_pool_release, NULL ); // Update other info on the frame mlt_properties_set_int( properties, "width", 720 ); mlt_properties_set_int( properties, "height", is_pal ? 576 : 480 ); mlt_properties_set_int( properties, "top_field_first", is_pal ? 0 : ( data[ 5 ] & 0x07 ) == 0 ? 0 : 1 ); } else { mlt_pool_release( data ); } // Update timecode on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Calculate the next timecode mlt_producer_prepare_next( producer ); return 0; }
frame_cache frame_cache_init( size_t size_max ) { // Empty frame cache is useless if ( size_max == 0 ) return NULL; frame_cache cache = calloc( 1, sizeof( struct frame_cache_s ) ); if ( cache != NULL ) { cache->frames = mlt_pool_alloc( size_max * sizeof( mlt_frame ) ); if ( cache->frames == NULL ) { free( cache ); return NULL; } cache->start_pos = 0; cache->frames_total = 0; cache->size = size_max; } return cache; }
mlt_consumer consumer_blipflash_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Allocate the consumer mlt_consumer consumer = mlt_consumer_new( profile ); mlt_properties consumer_properties = MLT_CONSUMER_PROPERTIES( consumer ); avsync_stats* stats = NULL; // If memory allocated and initializes without error if ( consumer != NULL ) { // Set up start/stop/terminated callbacks consumer->close = consumer_close; consumer->start = consumer_start; consumer->stop = consumer_stop; consumer->is_stopped = consumer_is_stopped; stats = mlt_pool_alloc( sizeof( avsync_stats ) ); stats->flash_history_count = 0; stats->blip_history_count = 0; stats->blip_in_progress = 0; stats->samples_since_blip = 0; stats->blip = 0; stats->flash = 0; stats->sample_offset = INT_MAX; stats->report_frames = 0; stats->out_file = stdout; if ( arg != NULL ) { FILE* out_file = fopen( arg, "w" ); if ( out_file != NULL ) stats->out_file = out_file; } mlt_properties_set_data( consumer_properties, "_stats", stats, 0, NULL, NULL ); mlt_properties_set( consumer_properties, "report", "blip" ); } // Return this return consumer; }
static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { // Obtain properties of frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); // Obtain the producer for this frame mlt_producer producer = mlt_properties_get_data( properties, "producer_frei0r", NULL ); // Obtain properties of producer mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer ); // Choose suitable out values if nothing specific requested if ( *width <= 0 ) *width = mlt_service_profile( MLT_PRODUCER_SERVICE(producer) )->width; if ( *height <= 0 ) *height = mlt_service_profile( MLT_PRODUCER_SERVICE(producer) )->height; // Allocate the image int size = *width * ( *height + 1 ) * 4; // Allocate the image *buffer = mlt_pool_alloc( size ); // Update the frame mlt_frame_set_image( frame, *buffer, size, mlt_pool_release ); *format = mlt_image_rgb24a; if ( *buffer != NULL ) { double position = mlt_frame_get_position( frame ); mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ); double time = position / mlt_profile_fps( profile ); process_frei0r_item( MLT_PRODUCER_SERVICE(producer), position, time, producer_props, frame, buffer, width, height ); } return 0; }
static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { context cx = mlt_frame_pop_service( frame ); mlt_frame nested_frame = mlt_frame_pop_service( frame ); *width = cx->profile->width; *height = cx->profile->height; int result = mlt_frame_get_image( nested_frame, image, format, width, height, writable ); // Allocate the image int size = *width * *height * ( *format == mlt_image_yuv422 ? 2 : *format == mlt_image_rgb24 ? 3 : ( *format == mlt_image_rgb24a || *format == mlt_image_opengl ) ? 4 : ( 3 / 2 ) ); uint8_t *new_image = mlt_pool_alloc( size ); // Update the frame mlt_properties properties = mlt_frame_properties( frame ); mlt_properties_set_data( properties, "image", new_image, size, mlt_pool_release, NULL ); memcpy( new_image, *image, size ); mlt_properties_set( properties, "progressive", mlt_properties_get( MLT_FRAME_PROPERTIES(nested_frame), "progressive" ) ); *image = new_image; return result; }
void read_xml(mlt_properties properties) { // Convert file name string encoding. const char *resource = mlt_properties_get( properties, "resource" ); mlt_properties_set( properties, "_resource_utf8", resource ); mlt_properties_from_utf8( properties, "_resource_utf8", "_resource_local8" ); resource = mlt_properties_get( properties, "_resource_local8" ); FILE *f = fopen( resource, "r" ); if ( f != NULL ) { int size = 0; long lSize; if ( fseek (f , 0 , SEEK_END) < 0 ) goto error; lSize = ftell (f); if ( lSize <= 0 ) goto error; rewind (f); char *infile = (char*) mlt_pool_alloc(lSize); if ( infile ) { size = fread(infile,1,lSize,f); if ( size ) { infile[size] = '\0'; mlt_properties_set(properties, "_xmldata", infile); } mlt_pool_release( infile ); } error: fclose(f); } }
static int get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_frame b_frame = mlt_frame_pop_frame( a_frame ); mlt_properties properties = MLT_FRAME_PROPERTIES( a_frame ); mlt_transition transition = MLT_TRANSITION( mlt_frame_pop_service( a_frame ) ); uint8_t *b_image; int window_size = mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( transition ), "window_size" ); double psnr[3], ssim[3]; *format = mlt_image_yuv422; mlt_frame_get_image( b_frame, &b_image, format, width, height, writable ); mlt_frame_get_image( a_frame, image, format, width, height, writable ); psnr[0] = calc_psnr( *image, b_image, *width * *height, 2 ); psnr[1] = calc_psnr( *image + 1, b_image + 1, *width * *height / 2, 4 ); psnr[2] = calc_psnr( *image + 3, b_image + 3, *width * *height / 2, 4 ); ssim[0] = calc_ssim( *image, b_image, *width, *height, window_size, 2 ); ssim[1] = calc_ssim( *image + 1, b_image + 1, *width / 2, *height, window_size, 4 ); ssim[2] = calc_ssim( *image + 3, b_image + 3, *width / 2, *height, window_size, 4 ); mlt_properties_set_double( properties, "meta.vqm.psnr.y", psnr[0] ); mlt_properties_set_double( properties, "meta.vqm.psnr.cb", psnr[1] ); mlt_properties_set_double( properties, "meta.vqm.psnr.cr", psnr[2] ); mlt_properties_set_double( properties, "meta.vqm.ssim.y", ssim[0] ); mlt_properties_set_double( properties, "meta.vqm.ssim.cb", ssim[1] ); mlt_properties_set_double( properties, "meta.vqm.ssim.cr", ssim[2] ); printf( "%05d %05.2f %05.2f %05.2f %5.3f %5.3f %5.3f\n", mlt_frame_get_position( a_frame ), psnr[0], psnr[1], psnr[2], ssim[0], ssim[1], ssim[2] ); // copy the B frame to the bottom of the A frame for comparison window_size = mlt_image_format_size( *format, *width, *height, NULL ) / 2; memcpy( *image + window_size, b_image + window_size, window_size ); if ( !mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( transition ), "render" ) ) return 0; // get RGBA image for Qt drawing *format = mlt_image_rgb24a; mlt_frame_get_image( a_frame, image, format, width, height, 1 ); // convert mlt image to qimage QImage img( *width, *height, QImage::Format_ARGB32 ); int y = *height + 1; uint8_t *src = *image; while ( --y ) { QRgb *dst = (QRgb*) img.scanLine( *height - y ); int x = *width + 1; while ( --x ) { *dst++ = qRgba( src[0], src[1], src[2], 255 ); src += 4; } } // setup Qt drawing QPainter painter; painter.begin( &img ); painter.setRenderHints( QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::HighQualityAntialiasing ); // draw some stuff with Qt QPalette palette; QFont font; QString s; font.setBold( true ); font.setPointSize( 30 * *height / 1080 ); painter.setPen( QColor("black") ); painter.drawLine( 0, *height/2 + 1, *width, *height/2 ); painter.setPen( QColor("white") ); painter.drawLine( 0, *height/2 - 1, *width, *height/2 ); painter.setFont( font ); s.sprintf( "Frame: %05d\nPSNR: %05.2f (Y) %05.2f (Cb) %05.2f (Cr)\nSSIM: %5.3f (Y) %5.3f (Cb) %5.3f (Cr)", mlt_frame_get_position( a_frame ), psnr[0], psnr[1], psnr[2], ssim[0], ssim[1], ssim[2] ); painter.setPen( QColor("black") ); painter.drawText( 52, *height * 8 / 10 + 2, *width, *height, 0, s ); painter.setPen( QColor("white") ); painter.drawText( 50, *height * 8 / 10, *width, *height, 0, s ); // finish Qt drawing painter.end(); window_size = mlt_image_format_size( *format, *width, *height, NULL ); uint8_t *dst = (uint8_t *) mlt_pool_alloc( window_size ); mlt_properties_set_data( MLT_FRAME_PROPERTIES(a_frame), "image", dst, window_size, mlt_pool_release, NULL ); *image = dst; // convert qimage to mlt y = *height + 1; while ( --y ) { QRgb *src = (QRgb*) img.scanLine( *height - y ); int x = *width + 1; while ( --x ) { *dst++ = qRed( *src ); *dst++ = qGreen( *src ); *dst++ = qBlue( *src ); *dst++ = qAlpha( *src ); src++; } } return 0; }
void refresh_image( producer_qimage self, mlt_frame frame, mlt_image_format format, int width, int height ) { // Obtain properties of frame and producer mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); mlt_producer producer = &self->parent; // Get index and qimage int image_idx = refresh_qimage( self, frame ); // optimization for subsequent iterations on single pictur if ( image_idx != self->image_idx || width != self->current_width || height != self->current_height ) self->current_image = NULL; // If we have a qimage and need a new scaled image if ( self->qimage && ( !self->current_image || ( format != mlt_image_none && format != self->format ) ) ) { char *interps = mlt_properties_get( properties, "rescale.interp" ); int interp = 0; QImage *qimage = static_cast<QImage*>( self->qimage ); // QImage has two scaling modes - we'll toggle between them here if ( strcmp( interps, "tiles" ) == 0 || strcmp( interps, "hyper" ) == 0 || strcmp( interps, "bicubic" ) == 0 ) interp = 1; // Note - the original qimage is already safe and ready for destruction if ( qimage->depth() == 1 ) { QImage temp = qimage->convertToFormat( QImage::Format_RGB32 ); delete qimage; qimage = new QImage( temp ); self->qimage = qimage; } QImage scaled = interp == 0 ? qimage->scaled( QSize( width, height ) ) : qimage->scaled( QSize(width, height), Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); int has_alpha = scaled.hasAlphaChannel(); // Store width and height self->current_width = width; self->current_height = height; // Allocate/define image int dst_stride = width * ( has_alpha ? 4 : 3 ); int image_size = dst_stride * ( height + 1 ); self->current_image = ( uint8_t * )mlt_pool_alloc( image_size ); self->current_alpha = NULL; self->format = has_alpha ? mlt_image_rgb24a : mlt_image_rgb24; // Copy the image int y = self->current_height + 1; uint8_t *dst = self->current_image; while ( --y ) { QRgb *src = (QRgb*) scaled.scanLine( self->current_height - y ); int x = self->current_width + 1; while ( --x ) { *dst++ = qRed(*src); *dst++ = qGreen(*src); *dst++ = qBlue(*src); if ( has_alpha ) *dst++ = qAlpha(*src); ++src; } } // Convert image to requested format if ( format != mlt_image_none && format != self->format ) { uint8_t *buffer = NULL; // First, set the image so it can be converted when we get it mlt_frame_replace_image( frame, self->current_image, self->format, width, height ); mlt_frame_set_image( frame, self->current_image, image_size, mlt_pool_release ); self->format = format; // get_image will do the format conversion mlt_frame_get_image( frame, &buffer, &format, &width, &height, 0 ); // cache copies of the image and alpha buffers if ( buffer ) { image_size = mlt_image_format_size( format, width, height, NULL ); self->current_image = (uint8_t*) mlt_pool_alloc( image_size ); memcpy( self->current_image, buffer, image_size ); } if ( ( buffer = mlt_frame_get_alpha_mask( frame ) ) ) { self->current_alpha = (uint8_t*) mlt_pool_alloc( width * height ); memcpy( self->current_alpha, buffer, width * height ); } } // Update the cache mlt_cache_item_close( self->image_cache ); mlt_service_cache_put( MLT_PRODUCER_SERVICE( producer ), "qimage.image", self->current_image, image_size, mlt_pool_release ); self->image_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.image" ); self->image_idx = image_idx; mlt_cache_item_close( self->alpha_cache ); self->alpha_cache = NULL; if ( self->current_alpha ) { mlt_service_cache_put( MLT_PRODUCER_SERVICE( producer ), "qimage.alpha", self->current_alpha, width * height, mlt_pool_release ); self->alpha_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.alpha" ); } } // Set width/height of frame mlt_properties_set_int( properties, "width", self->current_width ); mlt_properties_set_int( properties, "height", self->current_height ); }
static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { // Obtain properties of frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); // Obtain the producer for this frame mlt_producer producer = mlt_properties_get_data( properties, "producer_colour", NULL ); mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) ); // Obtain properties of producer mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer ); // Get the current and previous colour strings char *now = mlt_properties_get( producer_props, "resource" ); char *then = mlt_properties_get( producer_props, "_resource" ); // Get the current image and dimensions cached in the producer int size = 0; uint8_t *image = mlt_properties_get_data( producer_props, "image", &size ); int current_width = mlt_properties_get_int( producer_props, "_width" ); int current_height = mlt_properties_get_int( producer_props, "_height" ); mlt_image_format current_format = mlt_properties_get_int( producer_props, "_format" ); // Parse the colour if ( now && strchr( now, '/' ) ) { now = strdup( strrchr( now, '/' ) + 1 ); mlt_properties_set( producer_props, "resource", now ); free( now ); now = mlt_properties_get( producer_props, "resource" ); } mlt_color color = mlt_properties_get_color( producer_props, "resource" ); if ( mlt_properties_get( producer_props, "mlt_image_format") ) *format = mlt_image_format_id( mlt_properties_get( producer_props, "mlt_image_format") ); // Choose suitable out values if nothing specific requested if ( *format == mlt_image_none || *format == mlt_image_glsl ) *format = mlt_image_rgb24a; if ( *width <= 0 ) *width = mlt_service_profile( MLT_PRODUCER_SERVICE(producer) )->width; if ( *height <= 0 ) *height = mlt_service_profile( MLT_PRODUCER_SERVICE(producer) )->height; // Choose default image format if specific request is unsupported if (*format!=mlt_image_yuv420p && *format!=mlt_image_yuv422 && *format!=mlt_image_rgb24 && *format!= mlt_image_glsl && *format!= mlt_image_glsl_texture) *format = mlt_image_rgb24a; // See if we need to regenerate if ( !now || ( then && strcmp( now, then ) ) || *width != current_width || *height != current_height || *format != current_format ) { // Color the image int i = *width * *height + 1; int bpp; // Allocate the image size = mlt_image_format_size( *format, *width, *height, &bpp ); uint8_t *p = image = mlt_pool_alloc( size ); // Update the producer mlt_properties_set_data( producer_props, "image", image, size, mlt_pool_release, NULL ); mlt_properties_set_int( producer_props, "_width", *width ); mlt_properties_set_int( producer_props, "_height", *height ); mlt_properties_set_int( producer_props, "_format", *format ); mlt_properties_set( producer_props, "_resource", now ); mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); switch ( *format ) { case mlt_image_yuv420p: { int plane_size = *width * *height; uint8_t y, u, v; RGB2YUV_601_SCALED( color.r, color.g, color.b, y, u, v ); memset(p + 0, y, plane_size); memset(p + plane_size, u, plane_size/4); memset(p + plane_size + plane_size/4, v, plane_size/4); mlt_properties_set_int( properties, "colorspace", 601 ); break; } case mlt_image_yuv422: { int uneven = *width % 2; int count = ( *width - uneven ) / 2 + 1; uint8_t y, u, v; RGB2YUV_601_SCALED( color.r, color.g, color.b, y, u, v ); i = *height + 1; while ( --i ) { int j = count; while ( --j ) { *p ++ = y; *p ++ = u; *p ++ = y; *p ++ = v; } if ( uneven ) { *p ++ = y; *p ++ = u; } } mlt_properties_set_int( properties, "colorspace", 601 ); break; } case mlt_image_rgb24: while ( --i ) { *p ++ = color.r; *p ++ = color.g; *p ++ = color.b; } break; case mlt_image_glsl: case mlt_image_glsl_texture: memset(p, 0, size); break; case mlt_image_rgb24a: while ( --i ) { *p ++ = color.r; *p ++ = color.g; *p ++ = color.b; *p ++ = color.a; } break; default: mlt_log_error( MLT_PRODUCER_SERVICE( producer ), "invalid image format %s\n", mlt_image_format_name( *format ) ); } } else { mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); } // Create the alpha channel int alpha_size = 0; uint8_t *alpha = NULL; // Initialise the alpha if (color.a < 255 || *format == mlt_image_rgb24a) { alpha_size = *width * *height; alpha = mlt_pool_alloc( alpha_size ); if ( alpha ) memset( alpha, color.a, alpha_size ); else alpha_size = 0; } // Clone our image if (buffer && image && size > 0) { *buffer = mlt_pool_alloc( size ); memcpy( *buffer, image, size ); } // Now update properties so we free the copy after mlt_frame_set_image( frame, *buffer, size, mlt_pool_release ); mlt_frame_set_alpha( frame, alpha, alpha_size, mlt_pool_release ); mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( producer_props, "aspect_ratio" ) ); mlt_properties_set_int( properties, "meta.media.width", *width ); mlt_properties_set_int( properties, "meta.media.height", *height ); 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 = ( int )mlt_frame_pop_service( 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 -= 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_error( MLT_PRODUCER_SERVICE( producer ), "first_image == NULL get image died\n" ); 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; }