3 * \brief interface for all frame classes
6 * Copyright (C) 2003-2009 Ushodaya Enterprises Limited
7 * \author Charles Yates <charles.yates@pandora.be>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "mlt_frame.h"
25 #include "mlt_producer.h"
26 #include "mlt_factory.h"
27 #include "mlt_profile.h"
34 /** Construct a frame object.
36 * \public \memberof mlt_frame_s
37 * \param service the pointer to any service that can provide access to the profile
38 * \return a frame object on success or NULL if there was an allocation error
41 mlt_frame mlt_frame_init( mlt_service service )
44 mlt_frame self = calloc( 1, sizeof( struct mlt_frame_s ) );
48 mlt_profile profile = mlt_service_profile( service );
50 // Initialise the properties
51 mlt_properties properties = &self->parent;
52 mlt_properties_init( properties, self );
54 // Set default properties on the frame
55 mlt_properties_set_position( properties, "_position", 0.0 );
56 mlt_properties_set_data( properties, "image", NULL, 0, NULL, NULL );
57 mlt_properties_set_int( properties, "width", profile? profile->width : 720 );
58 mlt_properties_set_int( properties, "height", profile? profile->height : 576 );
59 mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( NULL ) );
60 mlt_properties_set_data( properties, "audio", NULL, 0, NULL, NULL );
61 mlt_properties_set_data( properties, "alpha", NULL, 0, NULL, NULL );
63 // Construct stacks for frames and methods
64 self->stack_image = mlt_deque_init( );
65 self->stack_audio = mlt_deque_init( );
66 self->stack_service = mlt_deque_init( );
72 /** Get a frame's properties.
74 * \public \memberof mlt_frame_s
76 * \return the frame's properties or NULL if an invalid frame is supplied
79 mlt_properties mlt_frame_properties( mlt_frame self )
81 return self != NULL ? &self->parent : NULL;
84 /** Determine if the frame will produce a test card image.
86 * \public \memberof mlt_frame_s
88 * \return true (non-zero) if this will produce from a test card
91 int mlt_frame_is_test_card( mlt_frame self )
93 return mlt_deque_count( self->stack_image ) == 0 || mlt_properties_get_int( MLT_FRAME_PROPERTIES( self ), "test_image" );
96 /** Determine if the frame will produce audio from a test card.
98 * \public \memberof mlt_frame_s
100 * \return true (non-zero) if this will produce from a test card
103 int mlt_frame_is_test_audio( mlt_frame self )
105 return mlt_deque_count( self->stack_audio ) == 0 || mlt_properties_get_int( MLT_FRAME_PROPERTIES( self ), "test_audio" );
108 /** Get the sample aspect ratio of the frame.
110 * \public \memberof mlt_frame_s
111 * \param self a frame
112 * \return the aspect ratio
115 double mlt_frame_get_aspect_ratio( mlt_frame self )
117 return mlt_properties_get_double( MLT_FRAME_PROPERTIES( self ), "aspect_ratio" );
120 /** Set the sample aspect ratio of the frame.
122 * \public \memberof mlt_frame_s
123 * \param self a frame
124 * \param value the new image sample aspect ratio
125 * \return true if error
128 int mlt_frame_set_aspect_ratio( mlt_frame self, double value )
130 return mlt_properties_set_double( MLT_FRAME_PROPERTIES( self ), "aspect_ratio", value );
133 /** Get the time position of this frame.
135 * This position is not necessarily the position as the original
136 * producer knows it. It could be the position that the playlist,
137 * multitrack, or tractor producer set.
139 * \public \memberof mlt_frame_s
140 * \param self a frame
141 * \return the position
142 * \see mlt_frame_original_position
145 mlt_position mlt_frame_get_position( mlt_frame self )
147 int pos = mlt_properties_get_position( MLT_FRAME_PROPERTIES( self ), "_position" );
148 return pos < 0 ? 0 : pos;
151 /** Get the original time position of this frame.
153 * This is the position that the original producer set on the frame.
155 * \public \memberof mlt_frame_s
156 * \param self a frame
157 * \return the position
160 mlt_position mlt_frame_original_position( mlt_frame self )
162 int pos = mlt_properties_get_position( MLT_FRAME_PROPERTIES( self ), "original_position" );
163 return pos < 0 ? 0 : pos;
166 /** Set the time position of this frame.
168 * \public \memberof mlt_frame_s
169 * \param self a frame
170 * \param value the position
171 * \return true if error
174 int mlt_frame_set_position( mlt_frame self, mlt_position value )
176 // Only set the original_position the first time.
177 if ( ! mlt_properties_get( MLT_FRAME_PROPERTIES( self ), "original_position" ) )
178 mlt_properties_set_position( MLT_FRAME_PROPERTIES( self ), "original_position", value );
179 return mlt_properties_set_position( MLT_FRAME_PROPERTIES( self ), "_position", value );
182 /** Stack a get_image callback.
184 * \public \memberof mlt_frame_s
185 * \param self a frame
186 * \param the get_image callback
187 * \return true if error
190 int mlt_frame_push_get_image( mlt_frame self, mlt_get_image get_image )
192 return mlt_deque_push_back( self->stack_image, get_image );
195 /** Pop a get_image callback.
197 * \public \memberof mlt_frame_s
198 * \param self a frame
199 * \return the get_image callback
202 mlt_get_image mlt_frame_pop_get_image( mlt_frame self )
204 return mlt_deque_pop_back( self->stack_image );
209 * \public \memberof mlt_frame_s
210 * \param self a frame
211 * \param that the frame to push onto \p self
212 * \return true if error
215 int mlt_frame_push_frame( mlt_frame self, mlt_frame that )
217 return mlt_deque_push_back( self->stack_image, that );
222 * \public \memberof mlt_frame_s
223 * \param self a frame
224 * \return a frame that was previously pushed
227 mlt_frame mlt_frame_pop_frame( mlt_frame self )
229 return mlt_deque_pop_back( self->stack_image );
234 * \public \memberof mlt_frame_s
235 * \param self a frame
236 * \param that an opaque pointer
237 * \return true if error
240 int mlt_frame_push_service( mlt_frame self, void *that )
242 return mlt_deque_push_back( self->stack_image, that );
247 * \public \memberof mlt_frame_s
248 * \param self a frame
249 * \return an opaque pointer to something previously pushed
252 void *mlt_frame_pop_service( mlt_frame self )
254 return mlt_deque_pop_back( self->stack_image );
259 * \public \memberof mlt_frame_s
260 * \param self a frame
261 * \param that an integer
262 * \return true if error
265 int mlt_frame_push_service_int( mlt_frame self, int that )
267 return mlt_deque_push_back_int( self->stack_image, that );
272 * \public \memberof mlt_frame_s
273 * \param self a frame
274 * \return an integer that was previously pushed
277 int mlt_frame_pop_service_int( mlt_frame self )
279 return mlt_deque_pop_back_int( self->stack_image );
282 /** Push an audio item on the stack.
284 * \public \memberof mlt_frame_s
285 * \param self a frame
286 * \param that an opaque pointer
287 * \return true if error
290 int mlt_frame_push_audio( mlt_frame self, void *that )
292 return mlt_deque_push_back( self->stack_audio, that );
295 /** Pop an audio item from the stack
297 * \public \memberof mlt_frame_s
298 * \param self a frame
299 * \return an opaque pointer to something that was pushed onto the frame's audio stack
302 void *mlt_frame_pop_audio( mlt_frame self )
304 return mlt_deque_pop_back( self->stack_audio );
307 /** Return the service stack
309 * \public \memberof mlt_frame_s
310 * \param self a frame
311 * \return the service stack
314 mlt_deque mlt_frame_service_stack( mlt_frame self )
316 return self->stack_service;
319 /** Set a new image on the frame.
321 * \public \memberof mlt_frame_s
322 * \param self a frame
323 * \param image a pointer to the raw image data
324 * \param size the size of the image data in bytes (optional)
325 * \param destroy a function to deallocate \p image when the frame is closed (optional)
326 * \return true if error
329 int mlt_frame_set_image( mlt_frame self, uint8_t *image, int size, mlt_destructor destroy )
331 return mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "image", image, size, destroy, NULL );
334 /** Set a new alpha channel on the frame.
336 * \public \memberof mlt_frame_s
337 * \param self a frame
338 * \param alpha a pointer to the alpha channel
339 * \param size the size of the alpha channel in bytes (optional)
340 * \param destroy a function to deallocate \p alpha when the frame is closed (optional)
341 * \return true if error
344 int mlt_frame_set_alpha( mlt_frame self, uint8_t *alpha, int size, mlt_destructor destroy )
346 self->get_alpha_mask = NULL;
347 return mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "alpha", alpha, size, destroy, NULL );
350 /** Replace image stack with the information provided.
352 * This might prove to be unreliable and restrictive - the idea is that a transition
353 * which normally uses two images may decide to only use the b frame (ie: in the case
354 * of a composite where the b frame completely obscures the a frame).
356 * The image must be writable and the destructor for the image itself must be taken
357 * care of on another frame and that frame cannot have a replace applied to it...
358 * Further it assumes that no alpha mask is in use.
360 * For these reasons, it can only be used in a specific situation - when you have
361 * multiple tracks each with their own transition and these transitions are applied
362 * in a strictly reversed order (ie: highest numbered [lowest track] is processed
365 * More reliable approach - the cases should be detected during the process phase
366 * and the upper tracks should simply not be invited to stack...
368 * \public \memberof mlt_frame_s
369 * \param self a frame
370 * \param image a new image
371 * \param format the image format
372 * \param width the width of the new image
373 * \param height the height of the new image
376 void mlt_frame_replace_image( mlt_frame self, uint8_t *image, mlt_image_format format, int width, int height )
378 // Remove all items from the stack
379 while( mlt_deque_pop_back( self->stack_image ) ) ;
381 // Update the information
382 mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "image", image, 0, NULL, NULL );
383 mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "width", width );
384 mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "height", height );
385 mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "format", format );
386 self->get_alpha_mask = NULL;
389 /** Get the short name for an image format.
391 * \public \memberof mlt_frame_s
392 * \param format the image format
396 const char * mlt_image_format_name( mlt_image_format format )
400 case mlt_image_none: return "none";
401 case mlt_image_rgb24: return "rgb24";
402 case mlt_image_rgb24a: return "rgb24a";
403 case mlt_image_yuv422: return "yuv422";
404 case mlt_image_yuv420p: return "yuv420p";
405 case mlt_image_opengl: return "opengl";
406 case mlt_image_glsl: return "glsl";
407 case mlt_image_glsl_texture: return "glsl_texture";
412 /** Get the number of bytes needed for an image.
414 * \public \memberof mlt_frame_s
415 * \param format the image format
416 * \param width width of the image in pixels
417 * \param height height of the image in pixels
418 * \param[out] bpp the number of bytes per pixel (optional)
419 * \return the number of bytes
421 int mlt_image_format_size( mlt_image_format format, int width, int height, int *bpp )
426 case mlt_image_rgb24:
428 return width * height * 3;
429 case mlt_image_opengl:
430 case mlt_image_rgb24a:
432 return width * height * 4;
433 case mlt_image_yuv422:
435 return width * height * 2;
436 case mlt_image_yuv420p:
437 if ( bpp ) *bpp = 3 / 2;
438 return width * height * 3 / 2;
446 /** Get the image associated to the frame.
448 * You should express the desired format, width, and height as inputs. As long
449 * as the loader producer was used to generate this or the imageconvert filter
450 * was attached, then you will get the image back in the format you desire.
451 * However, you do not always get the width and height you request depending
452 * on properties and filters. You do not need to supply a pre-allocated
453 * buffer, but you should always supply the desired image format.
455 * \public \memberof mlt_frame_s
456 * \param self a frame
457 * \param[out] buffer an image buffer
458 * \param[in,out] format the image format
459 * \param[in,out] width the horizontal size in pixels
460 * \param[in,out] height the vertical size in pixels
461 * \param writable whether or not you will need to be able to write to the memory returned in \p buffer
462 * \return true if error
463 * \todo Better describe the width and height as inputs.
466 int mlt_frame_get_image( mlt_frame self, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
468 mlt_properties properties = MLT_FRAME_PROPERTIES( self );
469 mlt_get_image get_image = mlt_frame_pop_get_image( self );
470 mlt_producer producer = mlt_properties_get_data( properties, "test_card_producer", NULL );
471 mlt_image_format requested_format = *format;
476 mlt_properties_set_int( properties, "image_count", mlt_properties_get_int( properties, "image_count" ) - 1 );
477 error = get_image( self, buffer, format, width, height, writable );
478 if ( !error && *buffer )
480 mlt_properties_set_int( properties, "width", *width );
481 mlt_properties_set_int( properties, "height", *height );
482 if ( self->convert_image && *buffer && requested_format != mlt_image_none )
483 self->convert_image( self, buffer, format, requested_format );
484 mlt_properties_set_int( properties, "format", *format );
488 // Cause the image to be loaded from test card or fallback (white) below.
489 mlt_frame_get_image( self, buffer, format, width, height, writable );
492 else if ( mlt_properties_get_data( properties, "image", NULL ) )
494 *format = mlt_properties_get_int( properties, "format" );
495 *buffer = mlt_properties_get_data( properties, "image", NULL );
496 *width = mlt_properties_get_int( properties, "width" );
497 *height = mlt_properties_get_int( properties, "height" );
498 if ( self->convert_image && *buffer && requested_format != mlt_image_none )
500 self->convert_image( self, buffer, format, requested_format );
501 mlt_properties_set_int( properties, "format", *format );
506 mlt_frame test_frame = NULL;
507 mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &test_frame, 0 );
510 mlt_properties test_properties = MLT_FRAME_PROPERTIES( test_frame );
511 mlt_properties_set( test_properties, "rescale.interp", mlt_properties_get( properties, "rescale.interp" ) );
512 mlt_frame_get_image( test_frame, buffer, format, width, height, writable );
513 mlt_properties_set_data( properties, "test_card_frame", test_frame, 0, ( mlt_destructor )mlt_frame_close, NULL );
514 mlt_properties_set_double( properties, "aspect_ratio", mlt_frame_get_aspect_ratio( test_frame ) );
515 // mlt_properties_set_data( properties, "image", *buffer, *width * *height * 2, NULL, NULL );
516 // mlt_properties_set_int( properties, "width", *width );
517 // mlt_properties_set_int( properties, "height", *height );
518 // mlt_properties_set_int( properties, "format", *format );
522 mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL );
523 mlt_frame_get_image( self, buffer, format, width, height, writable );
532 *width = *width == 0 ? 720 : *width;
533 *height = *height == 0 ? 576 : *height;
534 size = *width * *height;
536 mlt_properties_set_int( properties, "format", *format );
537 mlt_properties_set_int( properties, "width", *width );
538 mlt_properties_set_int( properties, "height", *height );
539 mlt_properties_set_int( properties, "aspect_ratio", 0 );
543 case mlt_image_rgb24:
546 *buffer = mlt_pool_alloc( size );
548 memset( *buffer, 255, size );
550 case mlt_image_rgb24a:
551 case mlt_image_opengl:
554 *buffer = mlt_pool_alloc( size );
556 memset( *buffer, 255, size );
558 case mlt_image_yuv422:
561 *buffer = mlt_pool_alloc( size );
564 while ( p != NULL && p != q )
570 case mlt_image_yuv420p:
572 *buffer = mlt_pool_alloc( size );
574 memset( *buffer, 255, size );
582 mlt_properties_set_data( properties, "image", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL );
583 mlt_properties_set_int( properties, "test_image", 1 );
589 /** Get the alpha channel associated to the frame.
591 * \public \memberof mlt_frame_s
592 * \param self a frame
593 * \return the alpha channel
596 uint8_t *mlt_frame_get_alpha_mask( mlt_frame self )
598 uint8_t *alpha = NULL;
601 if ( self->get_alpha_mask != NULL )
602 alpha = self->get_alpha_mask( self );
604 alpha = mlt_properties_get_data( &self->parent, "alpha", NULL );
607 int size = mlt_properties_get_int( &self->parent, "width" ) * mlt_properties_get_int( &self->parent, "height" );
608 alpha = mlt_pool_alloc( size );
609 memset( alpha, 255, size );
610 mlt_properties_set_data( &self->parent, "alpha", alpha, size, mlt_pool_release, NULL );
616 /** Get the short name for an audio format.
618 * You do not need to deallocate the returned string.
619 * \public \memberof mlt_frame_s
620 * \param format an audio format enum
621 * \return a string for the name of the image format
624 const char * mlt_audio_format_name( mlt_audio_format format )
628 case mlt_audio_none: return "none";
629 case mlt_audio_s16: return "s16";
630 case mlt_audio_s32: return "s32";
631 case mlt_audio_s32le: return "s32le";
632 case mlt_audio_float: return "float";
633 case mlt_audio_f32le: return "f32le";
634 case mlt_audio_u8: return "u8";
639 /** Get the amount of bytes needed for a block of audio.
641 * \public \memberof mlt_frame_s
642 * \param format an audio format enum
643 * \param samples the number of samples per channel
644 * \param channels the number of channels
645 * \return the number of bytes
648 int mlt_audio_format_size( mlt_audio_format format, int samples, int channels )
652 case mlt_audio_none: return 0;
653 case mlt_audio_s16: return samples * channels * sizeof( int16_t );
654 case mlt_audio_s32le:
655 case mlt_audio_s32: return samples * channels * sizeof( int32_t );
656 case mlt_audio_f32le:
657 case mlt_audio_float: return samples * channels * sizeof( float );
658 case mlt_audio_u8: return samples * channels;
663 /** Get the audio associated to the frame.
665 * You should express the desired format, frequency, channels, and samples as inputs. As long
666 * as the loader producer was used to generate this or the audioconvert filter
667 * was attached, then you will get the audio back in the format you desire.
668 * However, you do not always get the channels and samples you request depending
669 * on properties and filters. You do not need to supply a pre-allocated
670 * buffer, but you should always supply the desired audio format.
671 * The audio is always in interleaved format.
672 * You should use the \p mlt_sample_calculator to determine the number of samples you want.
674 * \public \memberof mlt_frame_s
675 * \param self a frame
676 * \param[out] buffer an audio buffer
677 * \param[in,out] format the audio format
678 * \param[in,out] frequency the sample rate
679 * \param[in,out] channels
680 * \param[in,out] samples the number of samples per frame
681 * \return true if error
684 int mlt_frame_get_audio( mlt_frame self, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
686 mlt_get_audio get_audio = mlt_frame_pop_audio( self );
687 mlt_properties properties = MLT_FRAME_PROPERTIES( self );
688 int hide = mlt_properties_get_int( properties, "test_audio" );
689 mlt_audio_format requested_format = *format;
691 if ( hide == 0 && get_audio != NULL )
693 get_audio( self, buffer, format, frequency, channels, samples );
694 mlt_properties_set_int( properties, "audio_frequency", *frequency );
695 mlt_properties_set_int( properties, "audio_channels", *channels );
696 mlt_properties_set_int( properties, "audio_samples", *samples );
697 mlt_properties_set_int( properties, "audio_format", *format );
698 if ( self->convert_audio && *buffer && requested_format != mlt_audio_none )
699 self->convert_audio( self, buffer, format, requested_format );
701 else if ( mlt_properties_get_data( properties, "audio", NULL ) )
703 *buffer = mlt_properties_get_data( properties, "audio", NULL );
704 *format = mlt_properties_get_int( properties, "audio_format" );
705 *frequency = mlt_properties_get_int( properties, "audio_frequency" );
706 *channels = mlt_properties_get_int( properties, "audio_channels" );
707 *samples = mlt_properties_get_int( properties, "audio_samples" );
708 if ( self->convert_audio && *buffer && requested_format != mlt_audio_none )
709 self->convert_audio( self, buffer, format, requested_format );
714 *samples = *samples <= 0 ? 1920 : *samples;
715 *channels = *channels <= 0 ? 2 : *channels;
716 *frequency = *frequency <= 0 ? 48000 : *frequency;
717 mlt_properties_set_int( properties, "audio_frequency", *frequency );
718 mlt_properties_set_int( properties, "audio_channels", *channels );
719 mlt_properties_set_int( properties, "audio_samples", *samples );
720 mlt_properties_set_int( properties, "audio_format", *format );
729 size = *samples * *channels * sizeof( int16_t );
732 size = *samples * *channels * sizeof( int32_t );
734 case mlt_audio_float:
735 size = *samples * *channels * sizeof( float );
741 *buffer = mlt_pool_alloc( size );
743 memset( *buffer, 0, size );
744 mlt_properties_set_data( properties, "audio", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL );
745 mlt_properties_set_int( properties, "test_audio", 1 );
748 // TODO: This does not belong here
749 if ( *format == mlt_audio_s16 && mlt_properties_get( properties, "meta.volume" ) )
751 double value = mlt_properties_get_double( properties, "meta.volume" );
755 memset( *buffer, 0, *samples * *channels * 2 );
757 else if ( value != 1.0 )
759 int total = *samples * *channels;
760 int16_t *p = *buffer;
768 mlt_properties_set( properties, "meta.volume", NULL );
774 /** Set the audio on a frame.
776 * \public \memberof mlt_frame_s
777 * \param self a frame
778 * \param buffer an buffer containing audio samples
779 * \param format the format of the audio in the \p buffer
780 * \param size the total size of the buffer (optional)
781 * \param destructor a function that releases or deallocates the \p buffer
782 * \return true if error
785 int mlt_frame_set_audio( mlt_frame self, void *buffer, mlt_audio_format format, int size, mlt_destructor destructor )
787 mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "audio_format", format );
788 return mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "audio", buffer, size, destructor, NULL );
791 /** Get audio on a frame as a waveform image.
793 * This generates an 8-bit grayscale image representation of the audio in a
794 * frame. Currently, this only really works for 2 channels.
795 * This allocates the bitmap using mlt_pool so you should release the return
796 * value with \p mlt_pool_release.
798 * \public \memberof mlt_frame_s
799 * \param self a frame
800 * \param w the width of the image
801 * \param h the height of the image to create
802 * \return a pointer to a new bitmap
805 unsigned char *mlt_frame_get_waveform( mlt_frame self, int w, int h )
808 mlt_properties properties = MLT_FRAME_PROPERTIES( self );
809 mlt_audio_format format = mlt_audio_s16;
810 int frequency = 16000;
812 mlt_producer producer = mlt_frame_get_original_producer( self );
813 double fps = mlt_producer_get_fps( mlt_producer_cut_parent( producer ) );
814 int samples = mlt_sample_calculator( fps, frequency, mlt_frame_get_position( self ) );
816 // Increase audio resolution proportional to requested image size
817 while ( samples < w )
820 samples = mlt_sample_calculator( fps, frequency, mlt_frame_get_position( self ) );
824 mlt_frame_get_audio( self, (void**)&pcm, &format, &frequency, &channels, &samples );
826 // Make an 8-bit buffer large enough to hold rendering
830 unsigned char *bitmap = ( unsigned char* )mlt_pool_alloc( size );
831 if ( bitmap != NULL )
832 memset( bitmap, 0, size );
835 mlt_properties_set_data( properties, "waveform", bitmap, size, ( mlt_destructor )mlt_pool_release, NULL );
837 // Render vertical lines
838 int16_t *ubound = pcm + samples * channels;
839 int skip = samples / w;
840 skip = !skip ? 1 : skip;
841 unsigned char gray = 0xFF / skip;
844 // Iterate sample stream and along x coordinate
845 for ( i = 0; pcm < ubound; i++ )
847 // pcm data has channels interleaved
848 for ( j = 0; j < channels; j++, pcm++ )
850 // Determine sample's magnitude from 2s complement;
851 int pcm_magnitude = *pcm < 0 ? ~(*pcm) + 1 : *pcm;
852 // The height of a line is the ratio of the magnitude multiplied by
853 // the vertical resolution of a single channel
854 int height = h * pcm_magnitude / channels / 2 / 32768;
855 // Determine the starting y coordinate - left top, right bottom
856 int displacement = h * (j * 2 + 1) / channels / 2 - ( *pcm < 0 ? 0 : height );
857 // Position buffer pointer using y coordinate, stride, and x coordinate
858 unsigned char *p = bitmap + i / skip + displacement * w;
860 // Draw vertical line
861 for ( k = 0; k < height + 1; k++ )
863 p[ w * k ] = ( k == 0 ) ? 0xFF : p[ w * k ] + gray;
865 p[ w * k ] = ( k == height ) ? 0xFF : p[ w * k ] + gray;
872 /** Get the end service that produced self frame.
874 * This fetches the first producer of the frame and not any producers that
877 * \public \memberof mlt_frame_s
878 * \param self a frame
882 mlt_producer mlt_frame_get_original_producer( mlt_frame self )
885 return mlt_properties_get_data( MLT_FRAME_PROPERTIES( self ), "_producer", NULL );
889 /** Destroy the frame.
891 * \public \memberof mlt_frame_s
892 * \param self a frame
895 void mlt_frame_close( mlt_frame self )
897 if ( self != NULL && mlt_properties_dec_ref( MLT_FRAME_PROPERTIES( self ) ) <= 0 )
899 mlt_deque_close( self->stack_image );
900 mlt_deque_close( self->stack_audio );
901 while( mlt_deque_peek_back( self->stack_service ) )
902 mlt_service_close( mlt_deque_pop_back( self->stack_service ) );
903 mlt_deque_close( self->stack_service );
904 mlt_properties_close( &self->parent );
909 /***** convenience functions *****/
911 /** Determine the number of samples that belong in a frame at a time position.
913 * \public \memberof mlt_frame_s
914 * \param fps the frame rate
915 * \param frequency the sample rate
916 * \param position the time position
917 * \return the number of samples per channel
920 int mlt_sample_calculator( float fps, int frequency, int64_t position )
922 /* Compute the cumulative number of samples until the start of this frame and the
923 cumulative number of samples until the start of the next frame. Round each to the
924 nearest integer and take the difference to determine the number of samples in
927 This approach should prevent rounding errors that can accumulate over a large number
928 of frames causing A/V sync problems. */
929 return mlt_sample_calculator_to_now( fps, frequency, position + 1 )
930 - mlt_sample_calculator_to_now( fps, frequency, position );
933 /** Determine the number of samples that belong before a time position.
935 * \public \memberof mlt_frame_s
936 * \param fps the frame rate
937 * \param frequency the sample rate
938 * \param position the time position
939 * \return the number of samples per channel
940 * \bug Will this break when mlt_position is converted to double?
943 int64_t mlt_sample_calculator_to_now( float fps, int frequency, int64_t position )
949 samples = (int64_t)( (double) position * (double) frequency / (double) fps +
950 ( position < 0 ? -0.5 : 0.5 ) );
956 void mlt_frame_write_ppm( mlt_frame frame )
960 mlt_image_format format = mlt_image_rgb24;
963 if ( mlt_frame_get_image( frame, &image, &format, &width, &height, 0 ) == 0 )
968 sprintf( filename, "frame-%05d.ppm", mlt_frame_get_position( frame ) );
969 file = fopen( filename, "wb" );
972 fprintf( file, "P6\n%d %d\n255\n", width, height);
973 fwrite( image, width * height * 3, 1, file );
978 /** Get or create a properties object unique to this service instance.
980 * Use this function to hold a service's processing parameters for this
981 * particular frame. Set the parameters in the service's process function.
982 * Then, get the parameters in the function it pushes to the frame's audio
983 * or image stack. This makes the service more parallel by reducing race
984 * conditions and less sensitive to multiple instances (by not setting a
985 * non-unique property on the frame). Creation and destruction of the
986 * properties object is handled automatically.
988 * \public \memberof mlt_frame_s
989 * \param self a frame
990 * \param service a service
991 * \return a properties object
994 mlt_properties mlt_frame_unique_properties( mlt_frame self, mlt_service service )
996 mlt_properties frame_props = MLT_FRAME_PROPERTIES( self );
997 mlt_properties service_props = MLT_SERVICE_PROPERTIES( service );
998 char *unique = mlt_properties_get( service_props, "_unique_id" );
999 mlt_properties instance_props = mlt_properties_get_data( frame_props, unique, NULL );
1001 if ( !instance_props )
1003 instance_props = mlt_properties_new();
1004 mlt_properties_set_data( frame_props, unique, instance_props, 0, (mlt_destructor) mlt_properties_close, NULL );
1007 return instance_props;
1010 /** Make a copy of a frame.
1012 * This does not copy the get_image/get_audio processing stacks or any
1013 * data properties other than the audio and image.
1015 * \public \memberof mlt_frame_s
1016 * \param self the frame to clone
1017 * \param is_deep a boolean to indicate whether to make a deep copy of the audio
1018 * and video data chunks or to make a shallow copy by pointing to the supplied frame
1019 * \return a almost-complete copy of the frame
1020 * \todo copy the processing deques
1023 mlt_frame mlt_frame_clone( mlt_frame self, int is_deep )
1025 mlt_frame new_frame = mlt_frame_init( NULL );
1026 mlt_properties properties = MLT_FRAME_PROPERTIES( self );
1027 mlt_properties new_props = MLT_FRAME_PROPERTIES( new_frame );
1031 mlt_properties_inherit( new_props, properties );
1033 // Carry over some special data properties for the multi consumer.
1034 mlt_properties_set_data( new_props, "_producer",
1035 mlt_frame_get_original_producer( self ), 0, NULL, NULL );
1036 mlt_properties_set_data( new_props, "movit.convert",
1037 mlt_properties_get_data( properties, "movit.convert", NULL), 0, NULL, NULL );
1041 data = mlt_properties_get_data( properties, "audio", &size );
1045 size = mlt_audio_format_size( mlt_properties_get_int( properties, "audio_format" ),
1046 mlt_properties_get_int( properties, "audio_samples" ),
1047 mlt_properties_get_int( properties, "audio_channels" ) );
1048 copy = mlt_pool_alloc( size );
1049 memcpy( copy, data, size );
1050 mlt_properties_set_data( new_props, "audio", copy, size, mlt_pool_release, NULL );
1052 data = mlt_properties_get_data( properties, "image", &size );
1056 size = mlt_image_format_size( mlt_properties_get_int( properties, "format" ),
1057 mlt_properties_get_int( properties, "width" ),
1058 mlt_properties_get_int( properties, "height" ), NULL );
1059 copy = mlt_pool_alloc( size );
1060 memcpy( copy, data, size );
1061 mlt_properties_set_data( new_props, "image", copy, size, mlt_pool_release, NULL );
1063 data = mlt_properties_get_data( properties, "alpha", &size );
1067 size = mlt_properties_get_int( properties, "width" ) *
1068 mlt_properties_get_int( properties, "height" );
1069 copy = mlt_pool_alloc( size );
1070 memcpy( copy, data, size );
1071 mlt_properties_set_data( new_props, "alpha", copy, size, mlt_pool_release, NULL );
1077 // This frame takes a reference on the original frame since the data is a shallow copy.
1078 mlt_properties_inc_ref( properties );
1079 mlt_properties_set_data( new_props, "_cloned_frame", self, 0,
1080 (mlt_destructor) mlt_frame_close, NULL );
1083 data = mlt_properties_get_data( properties, "audio", &size );
1084 mlt_properties_set_data( new_props, "audio", data, size, NULL, NULL );
1085 data = mlt_properties_get_data( properties, "image", &size );
1086 mlt_properties_set_data( new_props, "image", data, size, NULL, NULL );
1087 data = mlt_properties_get_data( properties, "alpha", &size );
1088 mlt_properties_set_data( new_props, "alpha", data, size, NULL, NULL );