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 return mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "alpha", alpha, size, destroy, NULL );
328 /** Replace image stack with the information provided.
330 * This might prove to be unreliable and restrictive - the idea is that a transition
331 * which normally uses two images may decide to only use the b frame (ie: in the case
332 * of a composite where the b frame completely obscures the a frame).
334 * The image must be writable and the destructor for the image itself must be taken
335 * care of on another frame and that frame cannot have a replace applied to it...
336 * Further it assumes that no alpha mask is in use.
338 * For these reasons, it can only be used in a specific situation - when you have
339 * multiple tracks each with their own transition and these transitions are applied
340 * in a strictly reversed order (ie: highest numbered [lowest track] is processed
343 * More reliable approach - the cases should be detected during the process phase
344 * and the upper tracks should simply not be invited to stack...
346 * \public \memberof mlt_frame_s
347 * \param self a frame
348 * \param image a new image
349 * \param format the image format
350 * \param width the width of the new image
351 * \param height the height of the new image
354 void mlt_frame_replace_image( mlt_frame self, uint8_t *image, mlt_image_format format, int width, int height )
356 // Remove all items from the stack
357 while( mlt_deque_pop_back( self->stack_image ) ) ;
359 // Update the information
360 mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "image", image, 0, NULL, NULL );
361 mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "width", width );
362 mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "height", height );
363 mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "format", format );
364 self->get_alpha_mask = NULL;
367 /** Get the short name for an image format.
369 * \public \memberof mlt_frame_s
370 * \param format the image format
374 const char * mlt_image_format_name( mlt_image_format format )
378 case mlt_image_none: return "none";
379 case mlt_image_rgb24: return "rgb24";
380 case mlt_image_rgb24a: return "rgb24a";
381 case mlt_image_yuv422: return "yuv422";
382 case mlt_image_yuv420p: return "yuv420p";
383 case mlt_image_opengl: return "opengl";
388 /** Get the number of bytes needed for an image.
390 * \public \memberof mlt_frame_s
391 * \param format the image format
392 * \param width width of the image in pixels
393 * \param height height of the image in pixels
394 * \param[out] bpp the number of bytes per pixel (optional)
395 * \return the number of bytes
397 int mlt_image_format_size( mlt_image_format format, int width, int height, int *bpp )
405 case mlt_image_rgb24:
407 return width * height * 3;
408 case mlt_image_opengl:
409 case mlt_image_rgb24a:
411 return width * height * 4;
412 case mlt_image_yuv422:
414 return width * height * 2;
415 case mlt_image_yuv420p:
416 if ( bpp ) *bpp = 3 / 2;
417 return width * height * 3 / 2;
422 /** Get the image associated to the frame.
424 * You should express the desired format, width, and height as inputs. As long
425 * as the loader producer was used to generate this or the imageconvert filter
426 * was attached, then you will get the image back in the format you desire.
427 * However, you do not always get the width and height you request depending
428 * on properties and filters. You do not need to supply a pre-allocated
429 * buffer, but you should always supply the desired image format.
431 * \public \memberof mlt_frame_s
432 * \param self a frame
433 * \param[out] buffer an image buffer
434 * \param[in,out] format the image format
435 * \param[in,out] width the horizontal size in pixels
436 * \param[in,out] height the vertical size in pixels
437 * \param writable whether or not you will need to be able to write to the memory returned in \p buffer
438 * \return true if error
439 * \todo Better describe the width and height as inputs.
442 int mlt_frame_get_image( mlt_frame self, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
444 mlt_properties properties = MLT_FRAME_PROPERTIES( self );
445 mlt_get_image get_image = mlt_frame_pop_get_image( self );
446 mlt_producer producer = mlt_properties_get_data( properties, "test_card_producer", NULL );
447 mlt_image_format requested_format = *format;
452 mlt_properties_set_int( properties, "image_count", mlt_properties_get_int( properties, "image_count" ) - 1 );
453 error = get_image( self, buffer, format, width, height, writable );
454 if ( !error && *buffer )
456 mlt_properties_set_int( properties, "width", *width );
457 mlt_properties_set_int( properties, "height", *height );
458 if ( self->convert_image && *buffer )
459 self->convert_image( self, buffer, format, requested_format );
460 mlt_properties_set_int( properties, "format", *format );
464 // Cause the image to be loaded from test card or fallback (white) below.
465 mlt_frame_get_image( self, buffer, format, width, height, writable );
468 else if ( mlt_properties_get_data( properties, "image", NULL ) )
470 *format = mlt_properties_get_int( properties, "format" );
471 *buffer = mlt_properties_get_data( properties, "image", NULL );
472 *width = mlt_properties_get_int( properties, "width" );
473 *height = mlt_properties_get_int( properties, "height" );
474 if ( self->convert_image && *buffer )
476 self->convert_image( self, buffer, format, requested_format );
477 mlt_properties_set_int( properties, "format", *format );
482 mlt_frame test_frame = NULL;
483 mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &test_frame, 0 );
486 mlt_properties test_properties = MLT_FRAME_PROPERTIES( test_frame );
487 mlt_properties_set_double( test_properties, "consumer_aspect_ratio", mlt_properties_get_double( properties, "consumer_aspect_ratio" ) );
488 mlt_properties_set( test_properties, "rescale.interp", mlt_properties_get( properties, "rescale.interp" ) );
489 mlt_frame_get_image( test_frame, buffer, format, width, height, writable );
490 mlt_properties_set_data( properties, "test_card_frame", test_frame, 0, ( mlt_destructor )mlt_frame_close, NULL );
491 mlt_properties_set_double( properties, "aspect_ratio", mlt_frame_get_aspect_ratio( test_frame ) );
492 // mlt_properties_set_data( properties, "image", *buffer, *width * *height * 2, NULL, NULL );
493 // mlt_properties_set_int( properties, "width", *width );
494 // mlt_properties_set_int( properties, "height", *height );
495 // mlt_properties_set_int( properties, "format", *format );
499 mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL );
500 mlt_frame_get_image( self, buffer, format, width, height, writable );
509 *width = *width == 0 ? 720 : *width;
510 *height = *height == 0 ? 576 : *height;
511 size = *width * *height;
513 mlt_properties_set_int( properties, "format", *format );
514 mlt_properties_set_int( properties, "width", *width );
515 mlt_properties_set_int( properties, "height", *height );
516 mlt_properties_set_int( properties, "aspect_ratio", 0 );
524 case mlt_image_rgb24:
527 *buffer = mlt_pool_alloc( size );
529 memset( *buffer, 255, size );
531 case mlt_image_rgb24a:
532 case mlt_image_opengl:
535 *buffer = mlt_pool_alloc( size );
537 memset( *buffer, 255, size );
539 case mlt_image_yuv422:
542 *buffer = mlt_pool_alloc( size );
545 while ( p != NULL && p != q )
551 case mlt_image_yuv420p:
553 *buffer = mlt_pool_alloc( size );
555 memset( *buffer, 255, size );
559 mlt_properties_set_data( properties, "image", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL );
560 mlt_properties_set_int( properties, "test_image", 1 );
566 /** Get the alpha channel associated to the frame.
568 * \public \memberof mlt_frame_s
569 * \param self a frame
570 * \return the alpha channel
573 uint8_t *mlt_frame_get_alpha_mask( mlt_frame self )
575 uint8_t *alpha = NULL;
578 if ( self->get_alpha_mask != NULL )
579 alpha = self->get_alpha_mask( self );
581 alpha = mlt_properties_get_data( &self->parent, "alpha", NULL );
584 int size = mlt_properties_get_int( &self->parent, "width" ) * mlt_properties_get_int( &self->parent, "height" );
585 alpha = mlt_pool_alloc( size );
586 memset( alpha, 255, size );
587 mlt_properties_set_data( &self->parent, "alpha", alpha, size, mlt_pool_release, NULL );
593 /** Get the short name for an audio format.
595 * You do not need to deallocate the returned string.
596 * \public \memberof mlt_frame_s
597 * \param format an audio format enum
598 * \return a string for the name of the image format
601 const char * mlt_audio_format_name( mlt_audio_format format )
605 case mlt_audio_none: return "none";
606 case mlt_audio_s16: return "s16";
607 case mlt_audio_s32: return "s32";
608 case mlt_audio_float: return "float";
613 /** Get the amount of bytes needed for a block of audio.
615 * \public \memberof mlt_frame_s
616 * \param format an audio format enum
617 * \param samples the number of samples per channel
618 * \param channels the number of channels
619 * \return the number of bytes
622 int mlt_audio_format_size( mlt_audio_format format, int samples, int channels )
626 case mlt_audio_none: return 0;
627 case mlt_audio_s16: return samples * channels * sizeof( int16_t );
628 case mlt_audio_s32: return samples * channels * sizeof( int32_t );
629 case mlt_audio_float: return samples * channels * sizeof( float );
634 /** Get the audio associated to the frame.
636 * You should express the desired format, frequency, channels, and samples as inputs. As long
637 * as the loader producer was used to generate this or the audioconvert filter
638 * was attached, then you will get the audio back in the format you desire.
639 * However, you do not always get the channels and samples you request depending
640 * on properties and filters. You do not need to supply a pre-allocated
641 * buffer, but you should always supply the desired audio format.
642 * The audio is always in interleaved format.
643 * You should use the \p mlt_sample_calculator to determine the number of samples you want.
645 * \public \memberof mlt_frame_s
646 * \param self a frame
647 * \param[out] buffer an audio buffer
648 * \param[in,out] format the audio format
649 * \param[in,out] frequency the sample rate
650 * \param[in,out] channels
651 * \param[in,out] samples the number of samples per frame
652 * \return true if error
655 int mlt_frame_get_audio( mlt_frame self, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
657 mlt_get_audio get_audio = mlt_frame_pop_audio( self );
658 mlt_properties properties = MLT_FRAME_PROPERTIES( self );
659 int hide = mlt_properties_get_int( properties, "test_audio" );
660 mlt_audio_format requested_format = *format;
662 if ( hide == 0 && get_audio != NULL )
664 get_audio( self, buffer, format, frequency, channels, samples );
665 mlt_properties_set_int( properties, "audio_frequency", *frequency );
666 mlt_properties_set_int( properties, "audio_channels", *channels );
667 mlt_properties_set_int( properties, "audio_samples", *samples );
668 mlt_properties_set_int( properties, "audio_format", *format );
669 if ( self->convert_audio )
670 self->convert_audio( self, buffer, format, requested_format );
672 else if ( mlt_properties_get_data( properties, "audio", NULL ) )
674 *buffer = mlt_properties_get_data( properties, "audio", NULL );
675 *format = mlt_properties_get_int( properties, "audio_format" );
676 *frequency = mlt_properties_get_int( properties, "audio_frequency" );
677 *channels = mlt_properties_get_int( properties, "audio_channels" );
678 *samples = mlt_properties_get_int( properties, "audio_samples" );
679 if ( self->convert_audio )
680 self->convert_audio( self, buffer, format, requested_format );
685 *samples = *samples <= 0 ? 1920 : *samples;
686 *channels = *channels <= 0 ? 2 : *channels;
687 *frequency = *frequency <= 0 ? 48000 : *frequency;
688 mlt_properties_set_int( properties, "audio_frequency", *frequency );
689 mlt_properties_set_int( properties, "audio_channels", *channels );
690 mlt_properties_set_int( properties, "audio_samples", *samples );
691 mlt_properties_set_int( properties, "audio_format", *format );
700 size = *samples * *channels * sizeof( int16_t );
703 size = *samples * *channels * sizeof( int32_t );
705 case mlt_audio_float:
706 size = *samples * *channels * sizeof( float );
710 *buffer = mlt_pool_alloc( size );
712 memset( *buffer, 0, size );
713 mlt_properties_set_data( properties, "audio", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL );
714 mlt_properties_set_int( properties, "test_audio", 1 );
717 // TODO: This does not belong here
718 if ( *format == mlt_audio_s16 && mlt_properties_get( properties, "meta.volume" ) )
720 double value = mlt_properties_get_double( properties, "meta.volume" );
724 memset( *buffer, 0, *samples * *channels * 2 );
726 else if ( value != 1.0 )
728 int total = *samples * *channels;
729 int16_t *p = *buffer;
737 mlt_properties_set( properties, "meta.volume", NULL );
743 /** Set the audio on a frame.
745 * \public \memberof mlt_frame_s
746 * \param self a frame
747 * \param buffer an buffer containing audio samples
748 * \param format the format of the audio in the \p buffer
749 * \param size the total size of the buffer (optional)
750 * \param destructor a function that releases or deallocates the \p buffer
751 * \return true if error
754 int mlt_frame_set_audio( mlt_frame self, void *buffer, mlt_audio_format format, int size, mlt_destructor destructor )
756 mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "audio_format", format );
757 return mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "audio", buffer, size, destructor, NULL );
760 /** Get audio on a frame as a waveform image.
762 * This generates an 8-bit grayscale image representation of the audio in a
763 * frame. Currently, this only really works for 2 channels.
764 * This allocates the bitmap using mlt_pool so you should release the return
765 * value with \p mlt_pool_release.
767 * \public \memberof mlt_frame_s
768 * \param self a frame
769 * \param w the width of the image
770 * \param h the height of the image to create
771 * \return a pointer to a new bitmap
774 unsigned char *mlt_frame_get_waveform( mlt_frame self, int w, int h )
777 mlt_properties properties = MLT_FRAME_PROPERTIES( self );
778 mlt_audio_format format = mlt_audio_s16;
779 int frequency = 16000;
781 mlt_producer producer = mlt_frame_get_original_producer( self );
782 double fps = mlt_producer_get_fps( mlt_producer_cut_parent( producer ) );
783 int samples = mlt_sample_calculator( fps, frequency, mlt_frame_get_position( self ) );
785 // Increase audio resolution proportional to requested image size
786 while ( samples < w )
789 samples = mlt_sample_calculator( fps, frequency, mlt_frame_get_position( self ) );
793 mlt_frame_get_audio( self, (void**)&pcm, &format, &frequency, &channels, &samples );
795 // Make an 8-bit buffer large enough to hold rendering
797 unsigned char *bitmap = ( unsigned char* )mlt_pool_alloc( size );
798 if ( bitmap != NULL )
799 memset( bitmap, 0, size );
800 mlt_properties_set_data( properties, "waveform", bitmap, size, ( mlt_destructor )mlt_pool_release, NULL );
802 // Render vertical lines
803 int16_t *ubound = pcm + samples * channels;
804 int skip = samples / w;
805 skip = !skip ? 1 : skip;
806 unsigned char gray = 0xFF / skip;
809 // Iterate sample stream and along x coordinate
810 for ( i = 0; pcm < ubound; i++ )
812 // pcm data has channels interleaved
813 for ( j = 0; j < channels; j++, pcm++ )
815 // Determine sample's magnitude from 2s complement;
816 int pcm_magnitude = *pcm < 0 ? ~(*pcm) + 1 : *pcm;
817 // The height of a line is the ratio of the magnitude multiplied by
818 // the vertical resolution of a single channel
819 int height = h * pcm_magnitude / channels / 2 / 32768;
820 // Determine the starting y coordinate - left top, right bottom
821 int displacement = h * (j * 2 + 1) / channels / 2 - ( *pcm < 0 ? 0 : height );
822 // Position buffer pointer using y coordinate, stride, and x coordinate
823 unsigned char *p = bitmap + i / skip + displacement * w;
825 // Draw vertical line
826 for ( k = 0; k < height + 1; k++ )
828 p[ w * k ] = ( k == 0 ) ? 0xFF : p[ w * k ] + gray;
830 p[ w * k ] = ( k == height ) ? 0xFF : p[ w * k ] + gray;
837 /** Get the end service that produced self frame.
839 * This fetches the first producer of the frame and not any producers that
842 * \public \memberof mlt_frame_s
843 * \param self a frame
847 mlt_producer mlt_frame_get_original_producer( mlt_frame self )
850 return mlt_properties_get_data( MLT_FRAME_PROPERTIES( self ), "_producer", NULL );
854 /** Destroy the frame.
856 * \public \memberof mlt_frame_s
857 * \param self a frame
860 void mlt_frame_close( mlt_frame self )
862 if ( self != NULL && mlt_properties_dec_ref( MLT_FRAME_PROPERTIES( self ) ) <= 0 )
864 mlt_deque_close( self->stack_image );
865 mlt_deque_close( self->stack_audio );
866 while( mlt_deque_peek_back( self->stack_service ) )
867 mlt_service_close( mlt_deque_pop_back( self->stack_service ) );
868 mlt_deque_close( self->stack_service );
869 mlt_properties_close( &self->parent );
874 /***** convenience functions *****/
876 /** Determine the number of samples that belong in a frame at a time position.
878 * \public \memberof mlt_frame_s
879 * \param fps the frame rate
880 * \param frequency the sample rate
881 * \param position the time position
882 * \return the number of samples per channel
885 int mlt_sample_calculator( float fps, int frequency, int64_t position )
887 /* Compute the cumulative number of samples until the start of this frame and the
888 cumulative number of samples until the start of the next frame. Round each to the
889 nearest integer and take the difference to determine the number of samples in
892 This approach should prevent rounding errors that can accumulate over a large number
893 of frames causing A/V sync problems. */
894 return mlt_sample_calculator_to_now( fps, frequency, position + 1 )
895 - mlt_sample_calculator_to_now( fps, frequency, position );
898 /** Determine the number of samples that belong before a time position.
900 * \public \memberof mlt_frame_s
901 * \param fps the frame rate
902 * \param frequency the sample rate
903 * \param position the time position
904 * \return the number of samples per channel
905 * \bug Will this break when mlt_position is converted to double?
908 int64_t mlt_sample_calculator_to_now( float fps, int frequency, int64_t position )
914 samples = (int64_t)( (double) position * (double) frequency / (double) fps +
915 ( position < 0 ? -0.5 : 0.5 ) );
921 void mlt_frame_write_ppm( mlt_frame frame )
925 mlt_image_format format = mlt_image_rgb24;
928 if ( mlt_frame_get_image( frame, &image, &format, &width, &height, 0 ) == 0 )
933 sprintf( filename, "frame-%05d.ppm", mlt_frame_get_position( frame ) );
934 file = fopen( filename, "wb" );
937 fprintf( file, "P6\n%d %d\n255\n", width, height);
938 fwrite( image, width * height * 3, 1, file );
943 /** Get or create a properties object unique to this service instance.
945 * Use this function to hold a service's processing parameters for this
946 * particular frame. Set the parameters in the service's process function.
947 * Then, get the parameters in the function it pushes to the frame's audio
948 * or image stack. This makes the service more parallel by reducing race
949 * conditions and less sensitive to multiple instances (by not setting a
950 * non-unique property on the frame). Creation and destruction of the
951 * properties object is handled automatically.
953 * \public \memberof mlt_frame_s
954 * \param self a frame
955 * \param service a service
956 * \return a properties object
959 mlt_properties mlt_frame_unique_properties( mlt_frame self, mlt_service service )
961 mlt_properties frame_props = MLT_FRAME_PROPERTIES( self );
962 mlt_properties service_props = MLT_SERVICE_PROPERTIES( service );
963 char *unique = mlt_properties_get( service_props, "_unique_id" );
964 mlt_properties instance_props = mlt_properties_get_data( frame_props, unique, NULL );
966 if ( !instance_props )
968 instance_props = mlt_properties_new();
969 mlt_properties_set_data( frame_props, unique, instance_props, 0, (mlt_destructor) mlt_properties_close, NULL );
972 return instance_props;