X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fframework%2Fmlt_frame.c;h=7c8b5f83145a30a26cf429b223d955f9ea3c5905;hb=7601aa4468f96fb8e3395266b194e7e7bd095453;hp=71ea33e52623ef1c618e93f6cf087a68fd101a48;hpb=584a646e9279588b3b45a54f2ec499e13bbc21c0;p=mlt diff --git a/src/framework/mlt_frame.c b/src/framework/mlt_frame.c index 71ea33e5..7c8b5f83 100644 --- a/src/framework/mlt_frame.c +++ b/src/framework/mlt_frame.c @@ -41,7 +41,7 @@ mlt_frame mlt_frame_init( mlt_service service ) { // Allocate a frame - mlt_frame self = calloc( sizeof( struct mlt_frame_s ), 1 ); + mlt_frame self = calloc( 1, sizeof( struct mlt_frame_s ) ); if ( self != NULL ) { @@ -56,8 +56,6 @@ mlt_frame mlt_frame_init( mlt_service service ) mlt_properties_set_data( properties, "image", NULL, 0, NULL, NULL ); mlt_properties_set_int( properties, "width", profile? profile->width : 720 ); mlt_properties_set_int( properties, "height", profile? profile->height : 576 ); - mlt_properties_set_int( properties, "normalised_width", profile? profile->width : 720 ); - mlt_properties_set_int( properties, "normalised_height", profile? profile->height : 576 ); mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( NULL ) ); mlt_properties_set_data( properties, "audio", NULL, 0, NULL, NULL ); mlt_properties_set_data( properties, "alpha", NULL, 0, NULL, NULL ); @@ -133,10 +131,15 @@ int mlt_frame_set_aspect_ratio( mlt_frame self, double value ) } /** Get the time position of this frame. + * + * This position is not necessarily the position as the original + * producer knows it. It could be the position that the playlist, + * multitrack, or tractor producer set. * * \public \memberof mlt_frame_s * \param self a frame * \return the position + * \see mlt_frame_original_position */ mlt_position mlt_frame_get_position( mlt_frame self ) @@ -145,6 +148,21 @@ mlt_position mlt_frame_get_position( mlt_frame self ) return pos < 0 ? 0 : pos; } +/** Get the original time position of this frame. + * + * This is the position that the original producer set on the frame. + * + * \public \memberof mlt_frame_s + * \param self a frame + * \return the position + */ + +mlt_position mlt_frame_original_position( mlt_frame self ) +{ + int pos = mlt_properties_get_position( MLT_FRAME_PROPERTIES( self ), "original_position" ); + return pos < 0 ? 0 : pos; +} + /** Set the time position of this frame. * * \public \memberof mlt_frame_s @@ -155,6 +173,9 @@ mlt_position mlt_frame_get_position( mlt_frame self ) int mlt_frame_set_position( mlt_frame self, mlt_position value ) { + // Only set the original_position the first time. + if ( ! mlt_properties_get( MLT_FRAME_PROPERTIES( self ), "original_position" ) ) + mlt_properties_set_position( MLT_FRAME_PROPERTIES( self ), "original_position", value ); return mlt_properties_set_position( MLT_FRAME_PROPERTIES( self ), "_position", value ); } @@ -322,6 +343,7 @@ int mlt_frame_set_image( mlt_frame self, uint8_t *image, int size, mlt_destructo int mlt_frame_set_alpha( mlt_frame self, uint8_t *alpha, int size, mlt_destructor destroy ) { + self->get_alpha_mask = NULL; return mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "alpha", alpha, size, destroy, NULL ); } @@ -381,6 +403,8 @@ const char * mlt_image_format_name( mlt_image_format format ) case mlt_image_yuv422: return "yuv422"; case mlt_image_yuv420p: return "yuv420p"; case mlt_image_opengl: return "opengl"; + case mlt_image_glsl: return "glsl"; + case mlt_image_glsl_texture: return "glsl_texture"; } return "invalid"; } @@ -399,9 +423,6 @@ int mlt_image_format_size( mlt_image_format format, int width, int height, int * height += 1; switch ( format ) { - case mlt_image_none: - if ( bpp ) *bpp = 0; - return 0; case mlt_image_rgb24: if ( bpp ) *bpp = 3; return width * height * 3; @@ -415,95 +436,46 @@ int mlt_image_format_size( mlt_image_format format, int width, int height, int * case mlt_image_yuv420p: if ( bpp ) *bpp = 3 / 2; return width * height * 3 / 2; + default: + if ( bpp ) *bpp = 0; + return 0; } return 0; } -/** Get the image associated to the frame. - * - * You should express the desired format, width, and height as inputs. As long - * as the loader producer was used to generate this or the imageconvert filter - * was attached, then you will get the image back in the format you desire. - * However, you do not always get the width and height you request depending - * on properties and filters. You do not need to supply a pre-allocated - * buffer, but you should always supply the desired image format. - * - * \public \memberof mlt_frame_s - * \param self a frame - * \param[out] buffer an image buffer - * \param[in,out] format the image format - * \param[in,out] width the horizontal size in pixels - * \param[in,out] height the vertical size in pixels - * \param writable whether or not you will need to be able to write to the memory returned in \p buffer - * \return true if error - * \todo Better describe the width and height as inputs. - */ - -int mlt_frame_get_image( mlt_frame self, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) +static int generate_test_image( mlt_properties properties, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { - mlt_properties properties = MLT_FRAME_PROPERTIES( self ); - mlt_get_image get_image = mlt_frame_pop_get_image( self ); mlt_producer producer = mlt_properties_get_data( properties, "test_card_producer", NULL ); mlt_image_format requested_format = *format; - int error = 0; + int error = 1; - if ( get_image ) - { - mlt_properties_set_int( properties, "image_count", mlt_properties_get_int( properties, "image_count" ) - 1 ); - error = get_image( self, buffer, format, width, height, writable ); - if ( !error && *buffer ) - { - mlt_properties_set_int( properties, "width", *width ); - mlt_properties_set_int( properties, "height", *height ); - if ( self->convert_image && *buffer ) - self->convert_image( self, buffer, format, requested_format ); - mlt_properties_set_int( properties, "format", *format ); - } - else - { - // Cause the image to be loaded from test card or fallback (white) below. - mlt_frame_get_image( self, buffer, format, width, height, writable ); - } - } - else if ( mlt_properties_get_data( properties, "image", NULL ) ) - { - *format = mlt_properties_get_int( properties, "format" ); - *buffer = mlt_properties_get_data( properties, "image", NULL ); - *width = mlt_properties_get_int( properties, "width" ); - *height = mlt_properties_get_int( properties, "height" ); - if ( self->convert_image && *buffer ) - { - self->convert_image( self, buffer, format, requested_format ); - mlt_properties_set_int( properties, "format", *format ); - } - } - else if ( producer ) + if ( producer ) { mlt_frame test_frame = NULL; mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &test_frame, 0 ); if ( test_frame ) { mlt_properties test_properties = MLT_FRAME_PROPERTIES( test_frame ); - mlt_properties_set_double( test_properties, "consumer_aspect_ratio", mlt_properties_get_double( properties, "consumer_aspect_ratio" ) ); - mlt_properties_set( test_properties, "rescale.interp", mlt_properties_get( properties, "rescale.interp" ) ); - mlt_frame_get_image( test_frame, buffer, format, width, height, writable ); mlt_properties_set_data( properties, "test_card_frame", test_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); - mlt_properties_set_double( properties, "aspect_ratio", mlt_frame_get_aspect_ratio( test_frame ) ); -// mlt_properties_set_data( properties, "image", *buffer, *width * *height * 2, NULL, NULL ); -// mlt_properties_set_int( properties, "width", *width ); -// mlt_properties_set_int( properties, "height", *height ); -// mlt_properties_set_int( properties, "format", *format ); + mlt_properties_set( test_properties, "rescale.interp", mlt_properties_get( properties, "rescale.interp" ) ); + error = mlt_frame_get_image( test_frame, buffer, format, width, height, writable ); + if ( !error && buffer && *buffer ) + { + mlt_properties_set_double( properties, "aspect_ratio", mlt_frame_get_aspect_ratio( test_frame ) ); + mlt_properties_set_int( properties, "width", *width ); + mlt_properties_set_int( properties, "height", *height ); + if ( test_frame->convert_image && requested_format != mlt_image_none ) + test_frame->convert_image( test_frame, buffer, format, requested_format ); + mlt_properties_set_int( properties, "format", *format ); + } } else { mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL ); - mlt_frame_get_image( self, buffer, format, width, height, writable ); } } - else + if ( error && buffer && *format != mlt_image_none ) { - register uint8_t *p; - register uint8_t *q; int size = 0; *width = *width == 0 ? 720 : *width; @@ -513,14 +485,10 @@ int mlt_frame_get_image( mlt_frame self, uint8_t **buffer, mlt_image_format *for mlt_properties_set_int( properties, "format", *format ); mlt_properties_set_int( properties, "width", *width ); mlt_properties_set_int( properties, "height", *height ); - mlt_properties_set_int( properties, "aspect_ratio", 0 ); + mlt_properties_set_double( properties, "aspect_ratio", 1.0 ); switch( *format ) { - case mlt_image_none: - size = 0; - *buffer = NULL; - break; case mlt_image_rgb24: size *= 3; size += *width * 3; @@ -540,24 +508,96 @@ int mlt_frame_get_image( mlt_frame self, uint8_t **buffer, mlt_image_format *for size *= 2; size += *width * 2; *buffer = mlt_pool_alloc( size ); - p = *buffer; - q = p + size; - while ( p != NULL && p != q ) + if ( *buffer ) { - *p ++ = 235; - *p ++ = 128; + register uint8_t *p = *buffer; + register uint8_t *q = p + size; + while ( p != NULL && p != q ) + { + *p ++ = 235; + *p ++ = 128; + } } break; case mlt_image_yuv420p: - size = size * 3 / 2; - *buffer = mlt_pool_alloc( size ); + *buffer = mlt_pool_alloc( size * 3 / 2 ); if ( *buffer ) - memset( *buffer, 255, size ); + { + memset( *buffer, 235, size ); + memset( *buffer + size, 128, size / 2 ); + } + break; + default: + size = 0; break; } - mlt_properties_set_data( properties, "image", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL ); mlt_properties_set_int( properties, "test_image", 1 ); + error = 0; + } + return error; +} + + +/** Get the image associated to the frame. + * + * You should express the desired format, width, and height as inputs. As long + * as the loader producer was used to generate this or the imageconvert filter + * was attached, then you will get the image back in the format you desire. + * However, you do not always get the width and height you request depending + * on properties and filters. You do not need to supply a pre-allocated + * buffer, but you should always supply the desired image format. + * + * \public \memberof mlt_frame_s + * \param self a frame + * \param[out] buffer an image buffer + * \param[in,out] format the image format + * \param[in,out] width the horizontal size in pixels + * \param[in,out] height the vertical size in pixels + * \param writable whether or not you will need to be able to write to the memory returned in \p buffer + * \return true if error + * \todo Better describe the width and height as inputs. + */ + +int mlt_frame_get_image( mlt_frame self, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) +{ + mlt_properties properties = MLT_FRAME_PROPERTIES( self ); + mlt_get_image get_image = mlt_frame_pop_get_image( self ); + mlt_image_format requested_format = *format; + int error = 0; + + if ( get_image ) + { + mlt_properties_set_int( properties, "image_count", mlt_properties_get_int( properties, "image_count" ) - 1 ); + error = get_image( self, buffer, format, width, height, writable ); + if ( !error && buffer && *buffer ) + { + mlt_properties_set_int( properties, "width", *width ); + mlt_properties_set_int( properties, "height", *height ); + if ( self->convert_image && requested_format != mlt_image_none ) + self->convert_image( self, buffer, format, requested_format ); + mlt_properties_set_int( properties, "format", *format ); + } + else + { + error = generate_test_image( properties, buffer, format, width, height, writable ); + } + } + else if ( mlt_properties_get_data( properties, "image", NULL ) && buffer ) + { + *format = mlt_properties_get_int( properties, "format" ); + *buffer = mlt_properties_get_data( properties, "image", NULL ); + *width = mlt_properties_get_int( properties, "width" ); + *height = mlt_properties_get_int( properties, "height" ); + if ( self->convert_image && *buffer && requested_format != mlt_image_none ) + { + self->convert_image( self, buffer, format, requested_format ); + mlt_properties_set_int( properties, "format", *format ); + } + } + else + { + error = generate_test_image( properties, buffer, format, width, height, writable ); } return error; @@ -594,8 +634,7 @@ uint8_t *mlt_frame_get_alpha_mask( mlt_frame self ) * * You do not need to deallocate the returned string. * \public \memberof mlt_frame_s - * \param self a frame - * \param format an image format enum + * \param format an audio format enum * \return a string for the name of the image format */ @@ -606,11 +645,38 @@ const char * mlt_audio_format_name( mlt_audio_format format ) case mlt_audio_none: return "none"; case mlt_audio_s16: return "s16"; case mlt_audio_s32: return "s32"; + case mlt_audio_s32le: return "s32le"; case mlt_audio_float: return "float"; + case mlt_audio_f32le: return "f32le"; + case mlt_audio_u8: return "u8"; } return "invalid"; } +/** Get the amount of bytes needed for a block of audio. + * + * \public \memberof mlt_frame_s + * \param format an audio format enum + * \param samples the number of samples per channel + * \param channels the number of channels + * \return the number of bytes + */ + +int mlt_audio_format_size( mlt_audio_format format, int samples, int channels ) +{ + switch ( format ) + { + case mlt_audio_none: return 0; + case mlt_audio_s16: return samples * channels * sizeof( int16_t ); + case mlt_audio_s32le: + case mlt_audio_s32: return samples * channels * sizeof( int32_t ); + case mlt_audio_f32le: + case mlt_audio_float: return samples * channels * sizeof( float ); + case mlt_audio_u8: return samples * channels; + } + return 0; +} + /** Get the audio associated to the frame. * * You should express the desired format, frequency, channels, and samples as inputs. As long @@ -646,7 +712,7 @@ int mlt_frame_get_audio( mlt_frame self, void **buffer, mlt_audio_format *format mlt_properties_set_int( properties, "audio_channels", *channels ); mlt_properties_set_int( properties, "audio_samples", *samples ); mlt_properties_set_int( properties, "audio_format", *format ); - if ( self->convert_audio ) + if ( self->convert_audio && *buffer && requested_format != mlt_audio_none ) self->convert_audio( self, buffer, format, requested_format ); } else if ( mlt_properties_get_data( properties, "audio", NULL ) ) @@ -656,7 +722,7 @@ int mlt_frame_get_audio( mlt_frame self, void **buffer, mlt_audio_format *format *frequency = mlt_properties_get_int( properties, "audio_frequency" ); *channels = mlt_properties_get_int( properties, "audio_channels" ); *samples = mlt_properties_get_int( properties, "audio_samples" ); - if ( self->convert_audio ) + if ( self->convert_audio && *buffer && requested_format != mlt_audio_none ) self->convert_audio( self, buffer, format, requested_format ); } else @@ -685,6 +751,8 @@ int mlt_frame_get_audio( mlt_frame self, void **buffer, mlt_audio_format *format case mlt_audio_float: size = *samples * *channels * sizeof( float ); break; + default: + break; } if ( size ) *buffer = mlt_pool_alloc( size ); @@ -774,9 +842,13 @@ unsigned char *mlt_frame_get_waveform( mlt_frame self, int w, int h ) // Make an 8-bit buffer large enough to hold rendering int size = w * h; + if ( size <= 0 ) + return NULL; unsigned char *bitmap = ( unsigned char* )mlt_pool_alloc( size ); if ( bitmap != NULL ) memset( bitmap, 0, size ); + else + return NULL; mlt_properties_set_data( properties, "waveform", bitmap, size, ( mlt_destructor )mlt_pool_release, NULL ); // Render vertical lines @@ -900,8 +972,8 @@ int64_t mlt_sample_calculator_to_now( float fps, int frequency, int64_t position void mlt_frame_write_ppm( mlt_frame frame ) { - int width; - int height; + int width = 0; + int height = 0; mlt_image_format format = mlt_image_rgb24; uint8_t *image; @@ -910,7 +982,7 @@ void mlt_frame_write_ppm( mlt_frame frame ) FILE *file; char filename[16]; - sprintf( filename, "frame-%05d.ppm", mlt_frame_get_position( frame ) ); + sprintf( filename, "frame-%05d.ppm", (int)mlt_frame_get_position( frame ) ); file = fopen( filename, "wb" ); if ( !file ) return; @@ -951,3 +1023,87 @@ mlt_properties mlt_frame_unique_properties( mlt_frame self, mlt_service service return instance_props; } + +/** Make a copy of a frame. + * + * This does not copy the get_image/get_audio processing stacks or any + * data properties other than the audio and image. + * + * \public \memberof mlt_frame_s + * \param self the frame to clone + * \param is_deep a boolean to indicate whether to make a deep copy of the audio + * and video data chunks or to make a shallow copy by pointing to the supplied frame + * \return a almost-complete copy of the frame + * \todo copy the processing deques + */ + +mlt_frame mlt_frame_clone( mlt_frame self, int is_deep ) +{ + mlt_frame new_frame = mlt_frame_init( NULL ); + mlt_properties properties = MLT_FRAME_PROPERTIES( self ); + mlt_properties new_props = MLT_FRAME_PROPERTIES( new_frame ); + void *data, *copy; + int size; + + mlt_properties_inherit( new_props, properties ); + + // Carry over some special data properties for the multi consumer. + mlt_properties_set_data( new_props, "_producer", + mlt_frame_get_original_producer( self ), 0, NULL, NULL ); + mlt_properties_set_data( new_props, "movit.convert", + mlt_properties_get_data( properties, "movit.convert", NULL), 0, NULL, NULL ); + + if ( is_deep ) + { + data = mlt_properties_get_data( properties, "audio", &size ); + if ( data ) + { + if ( !size ) + size = mlt_audio_format_size( mlt_properties_get_int( properties, "audio_format" ), + mlt_properties_get_int( properties, "audio_samples" ), + mlt_properties_get_int( properties, "audio_channels" ) ); + copy = mlt_pool_alloc( size ); + memcpy( copy, data, size ); + mlt_properties_set_data( new_props, "audio", copy, size, mlt_pool_release, NULL ); + } + data = mlt_properties_get_data( properties, "image", &size ); + if ( data ) + { + if ( ! size ) + size = mlt_image_format_size( mlt_properties_get_int( properties, "format" ), + mlt_properties_get_int( properties, "width" ), + mlt_properties_get_int( properties, "height" ), NULL ); + copy = mlt_pool_alloc( size ); + memcpy( copy, data, size ); + mlt_properties_set_data( new_props, "image", copy, size, mlt_pool_release, NULL ); + + data = mlt_properties_get_data( properties, "alpha", &size ); + if ( data ) + { + if ( ! size ) + size = mlt_properties_get_int( properties, "width" ) * + mlt_properties_get_int( properties, "height" ); + copy = mlt_pool_alloc( size ); + memcpy( copy, data, size ); + mlt_properties_set_data( new_props, "alpha", copy, size, mlt_pool_release, NULL ); + }; + } + } + else + { + // This frame takes a reference on the original frame since the data is a shallow copy. + mlt_properties_inc_ref( properties ); + mlt_properties_set_data( new_props, "_cloned_frame", self, 0, + (mlt_destructor) mlt_frame_close, NULL ); + + // Copy properties + data = mlt_properties_get_data( properties, "audio", &size ); + mlt_properties_set_data( new_props, "audio", data, size, NULL, NULL ); + data = mlt_properties_get_data( properties, "image", &size ); + mlt_properties_set_data( new_props, "image", data, size, NULL, NULL ); + data = mlt_properties_get_data( properties, "alpha", &size ); + mlt_properties_set_data( new_props, "alpha", data, size, NULL, NULL ); + } + + return new_frame; +}