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( sizeof( struct mlt_frame_s ), 1 );
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_int( properties, "normalised_width", profile? profile->width : 720 );
60 mlt_properties_set_int( properties, "normalised_height", profile? profile->height : 576 );
61 mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( NULL ) );
62 mlt_properties_set_data( properties, "audio", NULL, 0, NULL, NULL );
63 mlt_properties_set_data( properties, "alpha", NULL, 0, NULL, NULL );
65 // Construct stacks for frames and methods
66 self->stack_image = mlt_deque_init( );
67 self->stack_audio = mlt_deque_init( );
68 self->stack_service = mlt_deque_init( );
74 /** Get a frame's properties.
76 * \public \memberof mlt_frame_s
78 * \return the frame's properties or NULL if an invalid frame is supplied
81 mlt_properties mlt_frame_properties( mlt_frame self )
83 return self != NULL ? &self->parent : NULL;
86 /** Determine if the frame will produce a test card image.
88 * \public \memberof mlt_frame_s
90 * \return true (non-zero) if this will produce from a test card
93 int mlt_frame_is_test_card( mlt_frame self )
95 return mlt_deque_count( self->stack_image ) == 0 || mlt_properties_get_int( MLT_FRAME_PROPERTIES( self ), "test_image" );
98 /** Determine if the frame will produce audio from a test card.
100 * \public \memberof mlt_frame_s
101 * \param self a frame
102 * \return true (non-zero) if this will produce from a test card
105 int mlt_frame_is_test_audio( mlt_frame self )
107 return mlt_deque_count( self->stack_audio ) == 0 || mlt_properties_get_int( MLT_FRAME_PROPERTIES( self ), "test_audio" );
110 /** Get the sample aspect ratio of the frame.
112 * \public \memberof mlt_frame_s
113 * \param self a frame
114 * \return the aspect ratio
117 double mlt_frame_get_aspect_ratio( mlt_frame self )
119 return mlt_properties_get_double( MLT_FRAME_PROPERTIES( self ), "aspect_ratio" );
122 /** Set the sample aspect ratio of the frame.
124 * \public \memberof mlt_frame_s
125 * \param self a frame
126 * \param value the new image sample aspect ratio
127 * \return true if error
130 int mlt_frame_set_aspect_ratio( mlt_frame self, double value )
132 return mlt_properties_set_double( MLT_FRAME_PROPERTIES( self ), "aspect_ratio", value );
135 /** Get the time position of this frame.
137 * \public \memberof mlt_frame_s
138 * \param self a frame
139 * \return the position
142 mlt_position mlt_frame_get_position( mlt_frame self )
144 int pos = mlt_properties_get_position( MLT_FRAME_PROPERTIES( self ), "_position" );
145 return pos < 0 ? 0 : pos;
148 /** Set the time position of this frame.
150 * \public \memberof mlt_frame_s
151 * \param self a frame
152 * \param value the position
153 * \return true if error
156 int mlt_frame_set_position( mlt_frame self, mlt_position value )
158 return mlt_properties_set_position( MLT_FRAME_PROPERTIES( self ), "_position", value );
161 /** Stack a get_image callback.
163 * \public \memberof mlt_frame_s
164 * \param self a frame
165 * \param the get_image callback
166 * \return true if error
169 int mlt_frame_push_get_image( mlt_frame self, mlt_get_image get_image )
171 return mlt_deque_push_back( self->stack_image, get_image );
174 /** Pop a get_image callback.
176 * \public \memberof mlt_frame_s
177 * \param self a frame
178 * \return the get_image callback
181 mlt_get_image mlt_frame_pop_get_image( mlt_frame self )
183 return mlt_deque_pop_back( self->stack_image );
188 * \public \memberof mlt_frame_s
189 * \param self a frame
190 * \param that the frame to push onto \p self
191 * \return true if error
194 int mlt_frame_push_frame( mlt_frame self, mlt_frame that )
196 return mlt_deque_push_back( self->stack_image, that );
201 * \public \memberof mlt_frame_s
202 * \param self a frame
203 * \return a frame that was previously pushed
206 mlt_frame mlt_frame_pop_frame( mlt_frame self )
208 return mlt_deque_pop_back( self->stack_image );
213 * \public \memberof mlt_frame_s
214 * \param self a frame
215 * \param that an opaque pointer
216 * \return true if error
219 int mlt_frame_push_service( mlt_frame self, void *that )
221 return mlt_deque_push_back( self->stack_image, that );
226 * \public \memberof mlt_frame_s
227 * \param self a frame
228 * \return an opaque pointer to something previously pushed
231 void *mlt_frame_pop_service( mlt_frame self )
233 return mlt_deque_pop_back( self->stack_image );
238 * \public \memberof mlt_frame_s
239 * \param self a frame
240 * \param that an integer
241 * \return true if error
244 int mlt_frame_push_service_int( mlt_frame self, int that )
246 return mlt_deque_push_back_int( self->stack_image, that );
251 * \public \memberof mlt_frame_s
252 * \param self a frame
253 * \return an integer that was previously pushed
256 int mlt_frame_pop_service_int( mlt_frame self )
258 return mlt_deque_pop_back_int( self->stack_image );
261 /** Push an audio item on the stack.
263 * \public \memberof mlt_frame_s
264 * \param self a frame
265 * \param that an opaque pointer
266 * \return true if error
269 int mlt_frame_push_audio( mlt_frame self, void *that )
271 return mlt_deque_push_back( self->stack_audio, that );
274 /** Pop an audio item from the stack
276 * \public \memberof mlt_frame_s
277 * \param self a frame
278 * \return an opaque pointer to something that was pushed onto the frame's audio stack
281 void *mlt_frame_pop_audio( mlt_frame self )
283 return mlt_deque_pop_back( self->stack_audio );
286 /** Return the service stack
288 * \public \memberof mlt_frame_s
289 * \param self a frame
290 * \return the service stack
293 mlt_deque mlt_frame_service_stack( mlt_frame self )
295 return self->stack_service;
298 /** Set a new image on the frame.
300 * \public \memberof mlt_frame_s
301 * \param self a frame
302 * \param image a pointer to the raw image data
303 * \param size the size of the image data in bytes (optional)
304 * \param destroy a function to deallocate \p image when the frame is closed (optional)
305 * \return true if error
308 int mlt_frame_set_image( mlt_frame self, uint8_t *image, int size, mlt_destructor destroy )
310 return mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "image", image, size, destroy, NULL );
313 /** Set a new alpha channel on the frame.
315 * \public \memberof mlt_frame_s
316 * \param self a frame
317 * \param alpha a pointer to the alpha channel
318 * \param size the size of the alpha channel in bytes (optional)
319 * \param destroy a function to deallocate \p alpha when the frame is closed (optional)
320 * \return true if error
323 int mlt_frame_set_alpha( mlt_frame self, uint8_t *alpha, int size, mlt_destructor destroy )
325 self->get_alpha_mask = NULL;
326 return mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "alpha", alpha, size, destroy, NULL );
329 /** Replace image stack with the information provided.
331 * This might prove to be unreliable and restrictive - the idea is that a transition
332 * which normally uses two images may decide to only use the b frame (ie: in the case
333 * of a composite where the b frame completely obscures the a frame).
335 * The image must be writable and the destructor for the image itself must be taken
336 * care of on another frame and that frame cannot have a replace applied to it...
337 * Further it assumes that no alpha mask is in use.
339 * For these reasons, it can only be used in a specific situation - when you have
340 * multiple tracks each with their own transition and these transitions are applied
341 * in a strictly reversed order (ie: highest numbered [lowest track] is processed
344 * More reliable approach - the cases should be detected during the process phase
345 * and the upper tracks should simply not be invited to stack...
347 * \public \memberof mlt_frame_s
348 * \param self a frame
349 * \param image a new image
350 * \param format the image format
351 * \param width the width of the new image
352 * \param height the height of the new image
355 void mlt_frame_replace_image( mlt_frame self, uint8_t *image, mlt_image_format format, int width, int height )
357 // Remove all items from the stack
358 while( mlt_deque_pop_back( self->stack_image ) ) ;
360 // Update the information
361 mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "image", image, 0, NULL, NULL );
362 mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "width", width );
363 mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "height", height );
364 mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "format", format );
365 self->get_alpha_mask = NULL;
368 /** Get the short name for an image format.
370 * \public \memberof mlt_frame_s
371 * \param format the image format
375 const char * mlt_image_format_name( mlt_image_format format )
379 case mlt_image_none: return "none";
380 case mlt_image_rgb24: return "rgb24";
381 case mlt_image_rgb24a: return "rgb24a";
382 case mlt_image_yuv422: return "yuv422";
383 case mlt_image_yuv420p: return "yuv420p";
384 case mlt_image_opengl: return "opengl";
389 /** Get the number of bytes needed for an image.
391 * \public \memberof mlt_frame_s
392 * \param format the image format
393 * \param width width of the image in pixels
394 * \param height height of the image in pixels
395 * \param[out] bpp the number of bytes per pixel (optional)
396 * \return the number of bytes
398 int mlt_image_format_size( mlt_image_format format, int width, int height, int *bpp )
406 case mlt_image_rgb24:
408 return width * height * 3;
409 case mlt_image_opengl:
410 case mlt_image_rgb24a:
412 return width * height * 4;
413 case mlt_image_yuv422:
415 return width * height * 2;
416 case mlt_image_yuv420p:
417 if ( bpp ) *bpp = 3 / 2;
418 return width * height * 3 / 2;
423 /** Get the image associated to the frame.
425 * You should express the desired format, width, and height as inputs. As long
426 * as the loader producer was used to generate this or the imageconvert filter
427 * was attached, then you will get the image back in the format you desire.
428 * However, you do not always get the width and height you request depending
429 * on properties and filters. You do not need to supply a pre-allocated
430 * buffer, but you should always supply the desired image format.
432 * \public \memberof mlt_frame_s
433 * \param self a frame
434 * \param[out] buffer an image buffer
435 * \param[in,out] format the image format
436 * \param[in,out] width the horizontal size in pixels
437 * \param[in,out] height the vertical size in pixels
438 * \param writable whether or not you will need to be able to write to the memory returned in \p buffer
439 * \return true if error
440 * \todo Better describe the width and height as inputs.
443 int mlt_frame_get_image( mlt_frame self, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
445 mlt_properties properties = MLT_FRAME_PROPERTIES( self );
446 mlt_get_image get_image = mlt_frame_pop_get_image( self );
447 mlt_producer producer = mlt_properties_get_data( properties, "test_card_producer", NULL );
448 mlt_image_format requested_format = *format;
453 mlt_properties_set_int( properties, "image_count", mlt_properties_get_int( properties, "image_count" ) - 1 );
454 error = get_image( self, buffer, format, width, height, writable );
455 if ( !error && *buffer )
457 mlt_properties_set_int( properties, "width", *width );
458 mlt_properties_set_int( properties, "height", *height );
459 if ( self->convert_image && *buffer && requested_format != mlt_image_none )
460 self->convert_image( self, buffer, format, requested_format );
461 mlt_properties_set_int( properties, "format", *format );
465 // Cause the image to be loaded from test card or fallback (white) below.
466 mlt_frame_get_image( self, buffer, format, width, height, writable );
469 else if ( mlt_properties_get_data( properties, "image", NULL ) )
471 *format = mlt_properties_get_int( properties, "format" );
472 *buffer = mlt_properties_get_data( properties, "image", NULL );
473 *width = mlt_properties_get_int( properties, "width" );
474 *height = mlt_properties_get_int( properties, "height" );
475 if ( self->convert_image && *buffer && requested_format != mlt_image_none )
477 self->convert_image( self, buffer, format, requested_format );
478 mlt_properties_set_int( properties, "format", *format );
483 mlt_frame test_frame = NULL;
484 mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &test_frame, 0 );
487 mlt_properties test_properties = MLT_FRAME_PROPERTIES( test_frame );
488 mlt_properties_set_double( test_properties, "consumer_aspect_ratio", mlt_properties_get_double( properties, "consumer_aspect_ratio" ) );
489 mlt_properties_set( test_properties, "rescale.interp", mlt_properties_get( properties, "rescale.interp" ) );
490 mlt_frame_get_image( test_frame, buffer, format, width, height, writable );
491 mlt_properties_set_data( properties, "test_card_frame", test_frame, 0, ( mlt_destructor )mlt_frame_close, NULL );
492 mlt_properties_set_double( properties, "aspect_ratio", mlt_frame_get_aspect_ratio( test_frame ) );
493 // mlt_properties_set_data( properties, "image", *buffer, *width * *height * 2, NULL, NULL );
494 // mlt_properties_set_int( properties, "width", *width );
495 // mlt_properties_set_int( properties, "height", *height );
496 // mlt_properties_set_int( properties, "format", *format );
500 mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL );
501 mlt_frame_get_image( self, buffer, format, width, height, writable );
510 *width = *width == 0 ? 720 : *width;
511 *height = *height == 0 ? 576 : *height;
512 size = *width * *height;
514 mlt_properties_set_int( properties, "format", *format );
515 mlt_properties_set_int( properties, "width", *width );
516 mlt_properties_set_int( properties, "height", *height );
517 mlt_properties_set_int( properties, "aspect_ratio", 0 );
525 case mlt_image_rgb24:
528 *buffer = mlt_pool_alloc( size );
530 memset( *buffer, 255, size );
532 case mlt_image_rgb24a:
533 case mlt_image_opengl:
536 *buffer = mlt_pool_alloc( size );
538 memset( *buffer, 255, size );
540 case mlt_image_yuv422:
543 *buffer = mlt_pool_alloc( size );
546 while ( p != NULL && p != q )
552 case mlt_image_yuv420p:
554 *buffer = mlt_pool_alloc( size );
556 memset( *buffer, 255, size );
560 mlt_properties_set_data( properties, "image", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL );
561 mlt_properties_set_int( properties, "test_image", 1 );
567 /** Get the alpha channel associated to the frame.
569 * \public \memberof mlt_frame_s
570 * \param self a frame
571 * \return the alpha channel
574 uint8_t *mlt_frame_get_alpha_mask( mlt_frame self )
576 uint8_t *alpha = NULL;
579 if ( self->get_alpha_mask != NULL )
580 alpha = self->get_alpha_mask( self );
582 alpha = mlt_properties_get_data( &self->parent, "alpha", NULL );
585 int size = mlt_properties_get_int( &self->parent, "width" ) * mlt_properties_get_int( &self->parent, "height" );
586 alpha = mlt_pool_alloc( size );
587 memset( alpha, 255, size );
588 mlt_properties_set_data( &self->parent, "alpha", alpha, size, mlt_pool_release, NULL );
594 /** Get the short name for an audio format.
596 * You do not need to deallocate the returned string.
597 * \public \memberof mlt_frame_s
598 * \param format an audio format enum
599 * \return a string for the name of the image format
602 const char * mlt_audio_format_name( mlt_audio_format format )
606 case mlt_audio_none: return "none";
607 case mlt_audio_s16: return "s16";
608 case mlt_audio_s32: return "s32";
609 case mlt_audio_s32le: return "s32le";
610 case mlt_audio_float: return "float";
611 case mlt_audio_f32le: return "f32le";
616 /** Get the amount of bytes needed for a block of audio.
618 * \public \memberof mlt_frame_s
619 * \param format an audio format enum
620 * \param samples the number of samples per channel
621 * \param channels the number of channels
622 * \return the number of bytes
625 int mlt_audio_format_size( mlt_audio_format format, int samples, int channels )
629 case mlt_audio_none: return 0;
630 case mlt_audio_s16: return samples * channels * sizeof( int16_t );
631 case mlt_audio_s32le:
632 case mlt_audio_s32: return samples * channels * sizeof( int32_t );
633 case mlt_audio_f32le:
634 case mlt_audio_float: return samples * channels * sizeof( float );
639 /** Get the audio associated to the frame.
641 * You should express the desired format, frequency, channels, and samples as inputs. As long
642 * as the loader producer was used to generate this or the audioconvert filter
643 * was attached, then you will get the audio back in the format you desire.
644 * However, you do not always get the channels and samples you request depending
645 * on properties and filters. You do not need to supply a pre-allocated
646 * buffer, but you should always supply the desired audio format.
647 * The audio is always in interleaved format.
648 * You should use the \p mlt_sample_calculator to determine the number of samples you want.
650 * \public \memberof mlt_frame_s
651 * \param self a frame
652 * \param[out] buffer an audio buffer
653 * \param[in,out] format the audio format
654 * \param[in,out] frequency the sample rate
655 * \param[in,out] channels
656 * \param[in,out] samples the number of samples per frame
657 * \return true if error
660 int mlt_frame_get_audio( mlt_frame self, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
662 mlt_get_audio get_audio = mlt_frame_pop_audio( self );
663 mlt_properties properties = MLT_FRAME_PROPERTIES( self );
664 int hide = mlt_properties_get_int( properties, "test_audio" );
665 mlt_audio_format requested_format = *format;
667 if ( hide == 0 && get_audio != NULL )
669 get_audio( self, buffer, format, frequency, channels, samples );
670 mlt_properties_set_int( properties, "audio_frequency", *frequency );
671 mlt_properties_set_int( properties, "audio_channels", *channels );
672 mlt_properties_set_int( properties, "audio_samples", *samples );
673 mlt_properties_set_int( properties, "audio_format", *format );
674 if ( self->convert_audio && *buffer && requested_format != mlt_audio_none )
675 self->convert_audio( self, buffer, format, requested_format );
677 else if ( mlt_properties_get_data( properties, "audio", NULL ) )
679 *buffer = mlt_properties_get_data( properties, "audio", NULL );
680 *format = mlt_properties_get_int( properties, "audio_format" );
681 *frequency = mlt_properties_get_int( properties, "audio_frequency" );
682 *channels = mlt_properties_get_int( properties, "audio_channels" );
683 *samples = mlt_properties_get_int( properties, "audio_samples" );
684 if ( self->convert_audio && *buffer && requested_format != mlt_audio_none )
685 self->convert_audio( self, buffer, format, requested_format );
690 *samples = *samples <= 0 ? 1920 : *samples;
691 *channels = *channels <= 0 ? 2 : *channels;
692 *frequency = *frequency <= 0 ? 48000 : *frequency;
693 mlt_properties_set_int( properties, "audio_frequency", *frequency );
694 mlt_properties_set_int( properties, "audio_channels", *channels );
695 mlt_properties_set_int( properties, "audio_samples", *samples );
696 mlt_properties_set_int( properties, "audio_format", *format );
705 size = *samples * *channels * sizeof( int16_t );
708 size = *samples * *channels * sizeof( int32_t );
710 case mlt_audio_float:
711 size = *samples * *channels * sizeof( float );
717 *buffer = mlt_pool_alloc( size );
719 memset( *buffer, 0, size );
720 mlt_properties_set_data( properties, "audio", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL );
721 mlt_properties_set_int( properties, "test_audio", 1 );
724 // TODO: This does not belong here
725 if ( *format == mlt_audio_s16 && mlt_properties_get( properties, "meta.volume" ) )
727 double value = mlt_properties_get_double( properties, "meta.volume" );
731 memset( *buffer, 0, *samples * *channels * 2 );
733 else if ( value != 1.0 )
735 int total = *samples * *channels;
736 int16_t *p = *buffer;
744 mlt_properties_set( properties, "meta.volume", NULL );
750 /** Set the audio on a frame.
752 * \public \memberof mlt_frame_s
753 * \param self a frame
754 * \param buffer an buffer containing audio samples
755 * \param format the format of the audio in the \p buffer
756 * \param size the total size of the buffer (optional)
757 * \param destructor a function that releases or deallocates the \p buffer
758 * \return true if error
761 int mlt_frame_set_audio( mlt_frame self, void *buffer, mlt_audio_format format, int size, mlt_destructor destructor )
763 mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "audio_format", format );
764 return mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "audio", buffer, size, destructor, NULL );
767 /** Get audio on a frame as a waveform image.
769 * This generates an 8-bit grayscale image representation of the audio in a
770 * frame. Currently, this only really works for 2 channels.
771 * This allocates the bitmap using mlt_pool so you should release the return
772 * value with \p mlt_pool_release.
774 * \public \memberof mlt_frame_s
775 * \param self a frame
776 * \param w the width of the image
777 * \param h the height of the image to create
778 * \return a pointer to a new bitmap
781 unsigned char *mlt_frame_get_waveform( mlt_frame self, int w, int h )
784 mlt_properties properties = MLT_FRAME_PROPERTIES( self );
785 mlt_audio_format format = mlt_audio_s16;
786 int frequency = 16000;
788 mlt_producer producer = mlt_frame_get_original_producer( self );
789 double fps = mlt_producer_get_fps( mlt_producer_cut_parent( producer ) );
790 int samples = mlt_sample_calculator( fps, frequency, mlt_frame_get_position( self ) );
792 // Increase audio resolution proportional to requested image size
793 while ( samples < w )
796 samples = mlt_sample_calculator( fps, frequency, mlt_frame_get_position( self ) );
800 mlt_frame_get_audio( self, (void**)&pcm, &format, &frequency, &channels, &samples );
802 // Make an 8-bit buffer large enough to hold rendering
804 unsigned char *bitmap = ( unsigned char* )mlt_pool_alloc( size );
805 if ( bitmap != NULL )
806 memset( bitmap, 0, size );
807 mlt_properties_set_data( properties, "waveform", bitmap, size, ( mlt_destructor )mlt_pool_release, NULL );
809 // Render vertical lines
810 int16_t *ubound = pcm + samples * channels;
811 int skip = samples / w;
812 skip = !skip ? 1 : skip;
813 unsigned char gray = 0xFF / skip;
816 // Iterate sample stream and along x coordinate
817 for ( i = 0; pcm < ubound; i++ )
819 // pcm data has channels interleaved
820 for ( j = 0; j < channels; j++, pcm++ )
822 // Determine sample's magnitude from 2s complement;
823 int pcm_magnitude = *pcm < 0 ? ~(*pcm) + 1 : *pcm;
824 // The height of a line is the ratio of the magnitude multiplied by
825 // the vertical resolution of a single channel
826 int height = h * pcm_magnitude / channels / 2 / 32768;
827 // Determine the starting y coordinate - left top, right bottom
828 int displacement = h * (j * 2 + 1) / channels / 2 - ( *pcm < 0 ? 0 : height );
829 // Position buffer pointer using y coordinate, stride, and x coordinate
830 unsigned char *p = bitmap + i / skip + displacement * w;
832 // Draw vertical line
833 for ( k = 0; k < height + 1; k++ )
835 p[ w * k ] = ( k == 0 ) ? 0xFF : p[ w * k ] + gray;
837 p[ w * k ] = ( k == height ) ? 0xFF : p[ w * k ] + gray;
844 /** Get the end service that produced self frame.
846 * This fetches the first producer of the frame and not any producers that
849 * \public \memberof mlt_frame_s
850 * \param self a frame
854 mlt_producer mlt_frame_get_original_producer( mlt_frame self )
857 return mlt_properties_get_data( MLT_FRAME_PROPERTIES( self ), "_producer", NULL );
861 /** Destroy the frame.
863 * \public \memberof mlt_frame_s
864 * \param self a frame
867 void mlt_frame_close( mlt_frame self )
869 if ( self != NULL && mlt_properties_dec_ref( MLT_FRAME_PROPERTIES( self ) ) <= 0 )
871 mlt_deque_close( self->stack_image );
872 mlt_deque_close( self->stack_audio );
873 while( mlt_deque_peek_back( self->stack_service ) )
874 mlt_service_close( mlt_deque_pop_back( self->stack_service ) );
875 mlt_deque_close( self->stack_service );
876 mlt_properties_close( &self->parent );
881 /***** convenience functions *****/
883 /** Determine the number of samples that belong in a frame at a time position.
885 * \public \memberof mlt_frame_s
886 * \param fps the frame rate
887 * \param frequency the sample rate
888 * \param position the time position
889 * \return the number of samples per channel
892 int mlt_sample_calculator( float fps, int frequency, int64_t position )
894 /* Compute the cumulative number of samples until the start of this frame and the
895 cumulative number of samples until the start of the next frame. Round each to the
896 nearest integer and take the difference to determine the number of samples in
899 This approach should prevent rounding errors that can accumulate over a large number
900 of frames causing A/V sync problems. */
901 return mlt_sample_calculator_to_now( fps, frequency, position + 1 )
902 - mlt_sample_calculator_to_now( fps, frequency, position );
905 /** Determine the number of samples that belong before a time position.
907 * \public \memberof mlt_frame_s
908 * \param fps the frame rate
909 * \param frequency the sample rate
910 * \param position the time position
911 * \return the number of samples per channel
912 * \bug Will this break when mlt_position is converted to double?
915 int64_t mlt_sample_calculator_to_now( float fps, int frequency, int64_t position )
921 samples = (int64_t)( (double) position * (double) frequency / (double) fps +
922 ( position < 0 ? -0.5 : 0.5 ) );
928 void mlt_frame_write_ppm( mlt_frame frame )
932 mlt_image_format format = mlt_image_rgb24;
935 if ( mlt_frame_get_image( frame, &image, &format, &width, &height, 0 ) == 0 )
940 sprintf( filename, "frame-%05d.ppm", mlt_frame_get_position( frame ) );
941 file = fopen( filename, "wb" );
944 fprintf( file, "P6\n%d %d\n255\n", width, height);
945 fwrite( image, width * height * 3, 1, file );
950 /** Get or create a properties object unique to this service instance.
952 * Use this function to hold a service's processing parameters for this
953 * particular frame. Set the parameters in the service's process function.
954 * Then, get the parameters in the function it pushes to the frame's audio
955 * or image stack. This makes the service more parallel by reducing race
956 * conditions and less sensitive to multiple instances (by not setting a
957 * non-unique property on the frame). Creation and destruction of the
958 * properties object is handled automatically.
960 * \public \memberof mlt_frame_s
961 * \param self a frame
962 * \param service a service
963 * \return a properties object
966 mlt_properties mlt_frame_unique_properties( mlt_frame self, mlt_service service )
968 mlt_properties frame_props = MLT_FRAME_PROPERTIES( self );
969 mlt_properties service_props = MLT_SERVICE_PROPERTIES( service );
970 char *unique = mlt_properties_get( service_props, "_unique_id" );
971 mlt_properties instance_props = mlt_properties_get_data( frame_props, unique, NULL );
973 if ( !instance_props )
975 instance_props = mlt_properties_new();
976 mlt_properties_set_data( frame_props, unique, instance_props, 0, (mlt_destructor) mlt_properties_close, NULL );
979 return instance_props;
982 /** Make a copy of a frame.
984 * This does not copy the get_image/get_audio processing stacks or any
985 * data properties other than the audio and image.
987 * \public \memberof mlt_frame_s
988 * \param self the frame to clone
989 * \param is_deep a boolean to indicate whether to make a deep copy of the audio
990 * and video data chunks or to make a shallow copy by pointing to the supplied frame
991 * \return a almost-complete copy of the frame
992 * \todo copy the processing deques
995 mlt_frame mlt_frame_clone( mlt_frame self, int is_deep )
997 mlt_frame new_frame = mlt_frame_init( NULL );
998 mlt_properties properties = MLT_FRAME_PROPERTIES( self );
999 mlt_properties new_props = MLT_FRAME_PROPERTIES( new_frame );
1003 mlt_properties_inherit( new_props, properties );
1006 data = mlt_properties_get_data( properties, "audio", &size );
1010 size = mlt_audio_format_size( mlt_properties_get_int( properties, "audio_format" ),
1011 mlt_properties_get_int( properties, "audio_samples" ),
1012 mlt_properties_get_int( properties, "audio_channels" ) );
1013 copy = mlt_pool_alloc( size );
1014 memcpy( copy, data, size );
1015 mlt_properties_set_data( new_props, "audio", copy, size, mlt_pool_release, NULL );
1017 data = mlt_properties_get_data( properties, "image", &size );
1021 size = mlt_image_format_size( mlt_properties_get_int( properties, "format" ),
1022 mlt_properties_get_int( properties, "width" ),
1023 mlt_properties_get_int( properties, "height" ), NULL );
1024 copy = mlt_pool_alloc( size );
1025 memcpy( copy, data, size );
1026 mlt_properties_set_data( new_props, "image", copy, size, mlt_pool_release, NULL );
1028 data = mlt_properties_get_data( properties, "alpha", &size );
1032 size = mlt_properties_get_int( properties, "width" ) *
1033 mlt_properties_get_int( properties, "height" );
1034 copy = mlt_pool_alloc( size );
1035 memcpy( copy, data, size );
1036 mlt_properties_set_data( new_props, "alpha", copy, size, mlt_pool_release, NULL );
1042 // This frame takes a reference on the original frame since the data is a shallow copy.
1043 mlt_properties_inc_ref( properties );
1044 mlt_properties_set_data( new_props, "_cloned_frame", self, 0,
1045 (mlt_destructor) mlt_frame_close, NULL );
1048 data = mlt_properties_get_data( properties, "audio", &size );
1049 mlt_properties_set_data( new_props, "audio", data, size, NULL, NULL );
1050 data = mlt_properties_get_data( properties, "image", &size );
1051 mlt_properties_set_data( new_props, "image", data, size, NULL, NULL );
1052 data = mlt_properties_get_data( properties, "alpha", &size );
1053 mlt_properties_set_data( new_props, "alpha", data, size, NULL, NULL );