]> git.sesse.net Git - mlt/blob - src/framework/mlt_frame.c
Merge branch 'roto' of git://github.com/ttill/MLT-roto into roto
[mlt] / src / framework / mlt_frame.c
1 /**
2  * \file mlt_frame.c
3  * \brief interface for all frame classes
4  * \see mlt_frame_s
5  *
6  * Copyright (C) 2003-2009 Ushodaya Enterprises Limited
7  * \author Charles Yates <charles.yates@pandora.be>
8  *
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.
13  *
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.
18  *
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
22  */
23
24 #include "mlt_frame.h"
25 #include "mlt_producer.h"
26 #include "mlt_factory.h"
27 #include "mlt_profile.h"
28 #include "mlt_log.h"
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 /** Construct a frame object.
35  *
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
39  */
40
41 mlt_frame mlt_frame_init( mlt_service service )
42 {
43         // Allocate a frame
44         mlt_frame self = calloc( sizeof( struct mlt_frame_s ), 1 );
45
46         if ( self != NULL )
47         {
48                 mlt_profile profile = mlt_service_profile( service );
49
50                 // Initialise the properties
51                 mlt_properties properties = &self->parent;
52                 mlt_properties_init( properties, self );
53
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 );
64
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( );
69         }
70
71         return self;
72 }
73
74 /** Get a frame's properties.
75  *
76  * \public \memberof mlt_frame_s
77  * \param self a frame
78  * \return the frame's properties or NULL if an invalid frame is supplied
79  */
80
81 mlt_properties mlt_frame_properties( mlt_frame self )
82 {
83         return self != NULL ? &self->parent : NULL;
84 }
85
86 /** Determine if the frame will produce a test card image.
87  *
88  * \public \memberof mlt_frame_s
89  * \param self a frame
90  * \return true (non-zero) if this will produce from a test card
91  */
92
93 int mlt_frame_is_test_card( mlt_frame self )
94 {
95         return mlt_deque_count( self->stack_image ) == 0 || mlt_properties_get_int( MLT_FRAME_PROPERTIES( self ), "test_image" );
96 }
97
98 /** Determine if the frame will produce audio from a test card.
99  *
100  * \public \memberof mlt_frame_s
101  * \param self a frame
102  * \return true (non-zero) if this will produce from a test card
103  */
104
105 int mlt_frame_is_test_audio( mlt_frame self )
106 {
107         return mlt_deque_count( self->stack_audio ) == 0 || mlt_properties_get_int( MLT_FRAME_PROPERTIES( self ), "test_audio" );
108 }
109
110 /** Get the sample aspect ratio of the frame.
111  *
112  * \public \memberof  mlt_frame_s
113  * \param self a frame
114  * \return the aspect ratio
115  */
116
117 double mlt_frame_get_aspect_ratio( mlt_frame self )
118 {
119         return mlt_properties_get_double( MLT_FRAME_PROPERTIES( self ), "aspect_ratio" );
120 }
121
122 /** Set the sample aspect ratio of the frame.
123  *
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
128  */
129
130 int mlt_frame_set_aspect_ratio( mlt_frame self, double value )
131 {
132         return mlt_properties_set_double( MLT_FRAME_PROPERTIES( self ), "aspect_ratio", value );
133 }
134
135 /** Get the time position of this frame.
136  *
137  * \public \memberof mlt_frame_s
138  * \param self a frame
139  * \return the position
140  */
141
142 mlt_position mlt_frame_get_position( mlt_frame self )
143 {
144         int pos = mlt_properties_get_position( MLT_FRAME_PROPERTIES( self ), "_position" );
145         return pos < 0 ? 0 : pos;
146 }
147
148 /** Set the time position of this frame.
149  *
150  * \public \memberof mlt_frame_s
151  * \param self a frame
152  * \param value the position
153  * \return true if error
154  */
155
156 int mlt_frame_set_position( mlt_frame self, mlt_position value )
157 {
158         return mlt_properties_set_position( MLT_FRAME_PROPERTIES( self ), "_position", value );
159 }
160
161 /** Stack a get_image callback.
162  *
163  * \public \memberof mlt_frame_s
164  * \param self a frame
165  * \param the get_image callback
166  * \return true if error
167  */
168
169 int mlt_frame_push_get_image( mlt_frame self, mlt_get_image get_image )
170 {
171         return mlt_deque_push_back( self->stack_image, get_image );
172 }
173
174 /** Pop a get_image callback.
175  *
176  * \public \memberof mlt_frame_s
177  * \param self a frame
178  * \return the get_image callback
179  */
180
181 mlt_get_image mlt_frame_pop_get_image( mlt_frame self )
182 {
183         return mlt_deque_pop_back( self->stack_image );
184 }
185
186 /** Push a frame.
187  *
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
192  */
193
194 int mlt_frame_push_frame( mlt_frame self, mlt_frame that )
195 {
196         return mlt_deque_push_back( self->stack_image, that );
197 }
198
199 /** Pop a frame.
200  *
201  * \public \memberof mlt_frame_s
202  * \param self a frame
203  * \return a frame that was previously pushed
204  */
205
206 mlt_frame mlt_frame_pop_frame( mlt_frame self )
207 {
208         return mlt_deque_pop_back( self->stack_image );
209 }
210
211 /** Push a service.
212  *
213  * \public \memberof mlt_frame_s
214  * \param self a frame
215  * \param that an opaque pointer
216  * \return true if error
217  */
218
219 int mlt_frame_push_service( mlt_frame self, void *that )
220 {
221         return mlt_deque_push_back( self->stack_image, that );
222 }
223
224 /** Pop a service.
225  *
226  * \public \memberof mlt_frame_s
227  * \param self a frame
228  * \return an opaque pointer to something previously pushed
229  */
230
231 void *mlt_frame_pop_service( mlt_frame self )
232 {
233         return mlt_deque_pop_back( self->stack_image );
234 }
235
236 /** Push a number.
237  *
238  * \public \memberof mlt_frame_s
239  * \param self a frame
240  * \param that an integer
241  * \return true if error
242  */
243
244 int mlt_frame_push_service_int( mlt_frame self, int that )
245 {
246         return mlt_deque_push_back_int( self->stack_image, that );
247 }
248
249 /** Pop a number.
250  *
251  * \public \memberof mlt_frame_s
252  * \param self a frame
253  * \return an integer that was previously pushed
254  */
255
256 int mlt_frame_pop_service_int( mlt_frame self )
257 {
258         return mlt_deque_pop_back_int( self->stack_image );
259 }
260
261 /** Push an audio item on the stack.
262  *
263  * \public \memberof mlt_frame_s
264  * \param self a frame
265  * \param that an opaque pointer
266  * \return true if error
267  */
268
269 int mlt_frame_push_audio( mlt_frame self, void *that )
270 {
271         return mlt_deque_push_back( self->stack_audio, that );
272 }
273
274 /** Pop an audio item from the stack
275  *
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
279  */
280
281 void *mlt_frame_pop_audio( mlt_frame self )
282 {
283         return mlt_deque_pop_back( self->stack_audio );
284 }
285
286 /** Return the service stack
287  *
288  * \public \memberof mlt_frame_s
289  * \param self a frame
290  * \return the service stack
291  */
292
293 mlt_deque mlt_frame_service_stack( mlt_frame self )
294 {
295         return self->stack_service;
296 }
297
298 /** Replace image stack with the information provided.
299  *
300  * This might prove to be unreliable and restrictive - the idea is that a transition
301  * which normally uses two images may decide to only use the b frame (ie: in the case
302  * of a composite where the b frame completely obscures the a frame).
303  *
304  * The image must be writable and the destructor for the image itself must be taken
305  * care of on another frame and that frame cannot have a replace applied to it...
306  * Further it assumes that no alpha mask is in use.
307  *
308  * For these reasons, it can only be used in a specific situation - when you have
309  * multiple tracks each with their own transition and these transitions are applied
310  * in a strictly reversed order (ie: highest numbered [lowest track] is processed
311  * first).
312  *
313  * More reliable approach - the cases should be detected during the process phase
314  * and the upper tracks should simply not be invited to stack...
315  *
316  * \public \memberof mlt_frame_s
317  * \param self a frame
318  * \param image a new image
319  * \param format the image format
320  * \param width the width of the new image
321  * \param height the height of the new image
322  */
323
324 void mlt_frame_replace_image( mlt_frame self, uint8_t *image, mlt_image_format format, int width, int height )
325 {
326         // Remove all items from the stack
327         while( mlt_deque_pop_back( self->stack_image ) ) ;
328
329         // Update the information
330         mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "image", image, 0, NULL, NULL );
331         mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "width", width );
332         mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "height", height );
333         mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "format", format );
334         self->get_alpha_mask = NULL;
335 }
336
337 /** Get the short name for an image format.
338  *
339  * \public \memberof mlt_frame_s
340  * \param format the image format
341  * \return a string
342  */
343
344 const char * mlt_image_format_name( mlt_image_format format )
345 {
346         switch ( format )
347         {
348                 case mlt_image_none:    return "none";
349                 case mlt_image_rgb24:   return "rgb24";
350                 case mlt_image_rgb24a:  return "rgb24a";
351                 case mlt_image_yuv422:  return "yuv422";
352                 case mlt_image_yuv420p: return "yuv420p";
353                 case mlt_image_opengl:  return "opengl";
354         }
355         return "invalid";
356 }
357
358 /** Get the image associated to the frame.
359  *
360  * You should express the desired format, width, and height as inputs. As long
361  * as the loader producer was used to generate this or the imageconvert filter
362  * was attached, then you will get the image back in the format you desire.
363  * However, you do not always get the width and height you request depending
364  * on properties and filters. You do not need to supply a pre-allocated
365  * buffer, but you should always supply the desired image format.
366  *
367  * \public \memberof mlt_frame_s
368  * \param self a frame
369  * \param[out] buffer an image buffer
370  * \param[in,out] format the image format
371  * \param[in,out] width the horizontal size in pixels
372  * \param[in,out] height the vertical size in pixels
373  * \param writable whether or not you will need to be able to write to the memory returned in \p buffer
374  * \return true if error
375  * \todo Better describe the width and height as inputs.
376  */
377
378 int mlt_frame_get_image( mlt_frame self, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
379 {
380         mlt_properties properties = MLT_FRAME_PROPERTIES( self );
381         mlt_get_image get_image = mlt_frame_pop_get_image( self );
382         mlt_producer producer = mlt_properties_get_data( properties, "test_card_producer", NULL );
383         mlt_image_format requested_format = *format;
384         int error = 0;
385
386         if ( get_image )
387         {
388                 mlt_properties_set_int( properties, "image_count", mlt_properties_get_int( properties, "image_count" ) - 1 );
389                 error = get_image( self, buffer, format, width, height, writable );
390                 if ( !error && *buffer )
391                 {
392                         mlt_properties_set_int( properties, "width", *width );
393                         mlt_properties_set_int( properties, "height", *height );
394                         if ( self->convert_image && *buffer )
395                                 self->convert_image( self, buffer, format, requested_format );
396                         mlt_properties_set_int( properties, "format", *format );
397                 }
398                 else
399                 {
400                         // Cause the image to be loaded from test card or fallback (white) below.
401                         mlt_frame_get_image( self, buffer, format, width, height, writable );
402                 }
403         }
404         else if ( mlt_properties_get_data( properties, "image", NULL ) )
405         {
406                 *format = mlt_properties_get_int( properties, "format" );
407                 *buffer = mlt_properties_get_data( properties, "image", NULL );
408                 *width = mlt_properties_get_int( properties, "width" );
409                 *height = mlt_properties_get_int( properties, "height" );
410                 if ( self->convert_image && *buffer )
411                 {
412                         self->convert_image( self, buffer, format, requested_format );
413                         mlt_properties_set_int( properties, "format", *format );
414                 }
415         }
416         else if ( producer )
417         {
418                 mlt_frame test_frame = NULL;
419                 mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &test_frame, 0 );
420                 if ( test_frame )
421                 {
422                         mlt_properties test_properties = MLT_FRAME_PROPERTIES( test_frame );
423                         mlt_properties_set_double( test_properties, "consumer_aspect_ratio", mlt_properties_get_double( properties, "consumer_aspect_ratio" ) );
424                         mlt_properties_set( test_properties, "rescale.interp", mlt_properties_get( properties, "rescale.interp" ) );
425                         mlt_frame_get_image( test_frame, buffer, format, width, height, writable );
426                         mlt_properties_set_data( properties, "test_card_frame", test_frame, 0, ( mlt_destructor )mlt_frame_close, NULL );
427                         mlt_properties_set_double( properties, "aspect_ratio", mlt_frame_get_aspect_ratio( test_frame ) );
428 //                      mlt_properties_set_data( properties, "image", *buffer, *width * *height * 2, NULL, NULL );
429 //                      mlt_properties_set_int( properties, "width", *width );
430 //                      mlt_properties_set_int( properties, "height", *height );
431 //                      mlt_properties_set_int( properties, "format", *format );
432                 }
433                 else
434                 {
435                         mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL );
436                         mlt_frame_get_image( self, buffer, format, width, height, writable );
437                 }
438         }
439         else
440         {
441                 register uint8_t *p;
442                 register uint8_t *q;
443                 int size = 0;
444
445                 *width = *width == 0 ? 720 : *width;
446                 *height = *height == 0 ? 576 : *height;
447                 size = *width * *height;
448
449                 mlt_properties_set_int( properties, "format", *format );
450                 mlt_properties_set_int( properties, "width", *width );
451                 mlt_properties_set_int( properties, "height", *height );
452                 mlt_properties_set_int( properties, "aspect_ratio", 0 );
453
454                 switch( *format )
455                 {
456                         case mlt_image_none:
457                                 size = 0;
458                                 *buffer = NULL;
459                                 break;
460                         case mlt_image_rgb24:
461                                 size *= 3;
462                                 size += *width * 3;
463                                 *buffer = mlt_pool_alloc( size );
464                                 if ( *buffer )
465                                         memset( *buffer, 255, size );
466                                 break;
467                         case mlt_image_rgb24a:
468                         case mlt_image_opengl:
469                                 size *= 4;
470                                 size += *width * 4;
471                                 *buffer = mlt_pool_alloc( size );
472                                 if ( *buffer )
473                                         memset( *buffer, 255, size );
474                                 break;
475                         case mlt_image_yuv422:
476                                 size *= 2;
477                                 size += *width * 2;
478                                 *buffer = mlt_pool_alloc( size );
479                                 p = *buffer;
480                                 q = p + size;
481                                 while ( p != NULL && p != q )
482                                 {
483                                         *p ++ = 235;
484                                         *p ++ = 128;
485                                 }
486                                 break;
487                         case mlt_image_yuv420p:
488                                 size = size * 3 / 2;
489                                 *buffer = mlt_pool_alloc( size );
490                                 if ( *buffer )
491                                         memset( *buffer, 255, size );
492                                 break;
493                 }
494
495                 mlt_properties_set_data( properties, "image", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL );
496                 mlt_properties_set_int( properties, "test_image", 1 );
497         }
498
499         return error;
500 }
501
502 /** Get the alpha channel associated to the frame.
503  *
504  * \public \memberof mlt_frame_s
505  * \param self a frame
506  * \return the alpha channel
507  */
508
509 uint8_t *mlt_frame_get_alpha_mask( mlt_frame self )
510 {
511         uint8_t *alpha = NULL;
512         if ( self != NULL )
513         {
514                 if ( self->get_alpha_mask != NULL )
515                         alpha = self->get_alpha_mask( self );
516                 if ( alpha == NULL )
517                         alpha = mlt_properties_get_data( &self->parent, "alpha", NULL );
518                 if ( alpha == NULL )
519                 {
520                         int size = mlt_properties_get_int( &self->parent, "width" ) * mlt_properties_get_int( &self->parent, "height" );
521                         alpha = mlt_pool_alloc( size );
522                         memset( alpha, 255, size );
523                         mlt_properties_set_data( &self->parent, "alpha", alpha, size, mlt_pool_release, NULL );
524                 }
525         }
526         return alpha;
527 }
528
529 /** Get the short name for an audio format.
530  *
531  * You do not need to deallocate the returned string.
532  * \public \memberof mlt_frame_s
533  * \param self a frame
534  * \param format an image format enum
535  * \return a string for the name of the image format
536  */
537
538 const char * mlt_audio_format_name( mlt_audio_format format )
539 {
540         switch ( format )
541         {
542                 case mlt_audio_none:   return "none";
543                 case mlt_audio_s16:    return "s16";
544                 case mlt_audio_s32:    return "s32";
545                 case mlt_audio_float:  return "float";
546         }
547         return "invalid";
548 }
549
550 /** Get the audio associated to the frame.
551  *
552  * You should express the desired format, frequency, channels, and samples as inputs. As long
553  * as the loader producer was used to generate this or the audioconvert filter
554  * was attached, then you will get the audio back in the format you desire.
555  * However, you do not always get the channels and samples you request depending
556  * on properties and filters. You do not need to supply a pre-allocated
557  * buffer, but you should always supply the desired audio format.
558  * The audio is always in interleaved format.
559  * You should use the \p mlt_sample_calculator to determine the number of samples you want.
560  *
561  * \public \memberof mlt_frame_s
562  * \param self a frame
563  * \param[out] buffer an audio buffer
564  * \param[in,out] format the audio format
565  * \param[in,out] frequency the sample rate
566  * \param[in,out] channels
567  * \param[in,out] samples the number of samples per frame
568  * \return true if error
569  */
570
571 int mlt_frame_get_audio( mlt_frame self, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
572 {
573         mlt_get_audio get_audio = mlt_frame_pop_audio( self );
574         mlt_properties properties = MLT_FRAME_PROPERTIES( self );
575         int hide = mlt_properties_get_int( properties, "test_audio" );
576         mlt_audio_format requested_format = *format;
577
578         if ( hide == 0 && get_audio != NULL )
579         {
580                 get_audio( self, buffer, format, frequency, channels, samples );
581                 mlt_properties_set_int( properties, "audio_frequency", *frequency );
582                 mlt_properties_set_int( properties, "audio_channels", *channels );
583                 mlt_properties_set_int( properties, "audio_samples", *samples );
584                 mlt_properties_set_int( properties, "audio_format", *format );
585                 if ( self->convert_audio )
586                         self->convert_audio( self, buffer, format, requested_format );
587         }
588         else if ( mlt_properties_get_data( properties, "audio", NULL ) )
589         {
590                 *buffer = mlt_properties_get_data( properties, "audio", NULL );
591                 *format = mlt_properties_get_int( properties, "audio_format" );
592                 *frequency = mlt_properties_get_int( properties, "audio_frequency" );
593                 *channels = mlt_properties_get_int( properties, "audio_channels" );
594                 *samples = mlt_properties_get_int( properties, "audio_samples" );
595                 if ( self->convert_audio )
596                         self->convert_audio( self, buffer, format, requested_format );
597         }
598         else
599         {
600                 int size = 0;
601                 *samples = *samples <= 0 ? 1920 : *samples;
602                 *channels = *channels <= 0 ? 2 : *channels;
603                 *frequency = *frequency <= 0 ? 48000 : *frequency;
604                 mlt_properties_set_int( properties, "audio_frequency", *frequency );
605                 mlt_properties_set_int( properties, "audio_channels", *channels );
606                 mlt_properties_set_int( properties, "audio_samples", *samples );
607                 mlt_properties_set_int( properties, "audio_format", *format );
608
609                 switch( *format )
610                 {
611                         case mlt_image_none:
612                                 size = 0;
613                                 *buffer = NULL;
614                                 break;
615                         case mlt_audio_s16:
616                                 size = *samples * *channels * sizeof( int16_t );
617                                 break;
618                         case mlt_audio_s32:
619                                 size = *samples * *channels * sizeof( int32_t );
620                                 break;
621                         case mlt_audio_float:
622                                 size = *samples * *channels * sizeof( float );
623                                 break;
624                 }
625                 if ( size )
626                         *buffer = mlt_pool_alloc( size );
627                 if ( *buffer )
628                         memset( *buffer, 0, size );
629                 mlt_properties_set_data( properties, "audio", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL );
630                 mlt_properties_set_int( properties, "test_audio", 1 );
631         }
632
633         // TODO: This does not belong here
634         if ( *format == mlt_audio_s16 && mlt_properties_get( properties, "meta.volume" ) )
635         {
636                 double value = mlt_properties_get_double( properties, "meta.volume" );
637
638                 if ( value == 0.0 )
639                 {
640                         memset( *buffer, 0, *samples * *channels * 2 );
641                 }
642                 else if ( value != 1.0 )
643                 {
644                         int total = *samples * *channels;
645                         int16_t *p = *buffer;
646                         while ( total -- )
647                         {
648                                 *p = *p * value;
649                                 p ++;
650                         }
651                 }
652
653                 mlt_properties_set( properties, "meta.volume", NULL );
654         }
655
656         return 0;
657 }
658
659 /** Set the audio on a frame.
660  *
661  * \public \memberof mlt_frame_s
662  * \param self a frame
663  * \param buffer an buffer containing audio samples
664  * \param format the format of the audio in the \p buffer
665  * \param size the total size of the buffer (optional)
666  * \param destructor a function that releases or deallocates the \p buffer
667  * \return true if error
668  */
669
670 int mlt_frame_set_audio( mlt_frame self, void *buffer, mlt_audio_format format, int size, mlt_destructor destructor )
671 {
672         mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "audio_format", format );
673         return mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "audio", buffer, size, destructor, NULL );
674 }
675
676 /** Get audio on a frame as a waveform image.
677  *
678  * This generates an 8-bit grayscale image representation of the audio in a
679  * frame. Currently, this only really works for 2 channels.
680  * This allocates the bitmap using mlt_pool so you should release the return
681  * value with \p mlt_pool_release.
682  *
683  * \public \memberof mlt_frame_s
684  * \param self a frame
685  * \param w the width of the image
686  * \param h the height of the image to create
687  * \return a pointer to a new bitmap
688  */
689
690 unsigned char *mlt_frame_get_waveform( mlt_frame self, int w, int h )
691 {
692         int16_t *pcm = NULL;
693         mlt_properties properties = MLT_FRAME_PROPERTIES( self );
694         mlt_audio_format format = mlt_audio_s16;
695         int frequency = 16000;
696         int channels = 2;
697         mlt_producer producer = mlt_frame_get_original_producer( self );
698         double fps = mlt_producer_get_fps( mlt_producer_cut_parent( producer ) );
699         int samples = mlt_sample_calculator( fps, frequency, mlt_frame_get_position( self ) );
700
701         // Increase audio resolution proportional to requested image size
702         while ( samples < w )
703         {
704                 frequency += 16000;
705                 samples = mlt_sample_calculator( fps, frequency, mlt_frame_get_position( self ) );
706         }
707
708         // Get the pcm data
709         mlt_frame_get_audio( self, (void**)&pcm, &format, &frequency, &channels, &samples );
710
711         // Make an 8-bit buffer large enough to hold rendering
712         int size = w * h;
713         unsigned char *bitmap = ( unsigned char* )mlt_pool_alloc( size );
714         if ( bitmap != NULL )
715                 memset( bitmap, 0, size );
716         mlt_properties_set_data( properties, "waveform", bitmap, size, ( mlt_destructor )mlt_pool_release, NULL );
717
718         // Render vertical lines
719         int16_t *ubound = pcm + samples * channels;
720         int skip = samples / w;
721         skip = !skip ? 1 : skip;
722         unsigned char gray = 0xFF / skip;
723         int i, j, k;
724
725         // Iterate sample stream and along x coordinate
726         for ( i = 0; pcm < ubound; i++ )
727         {
728                 // pcm data has channels interleaved
729                 for ( j = 0; j < channels; j++, pcm++ )
730                 {
731                         // Determine sample's magnitude from 2s complement;
732                         int pcm_magnitude = *pcm < 0 ? ~(*pcm) + 1 : *pcm;
733                         // The height of a line is the ratio of the magnitude multiplied by
734                         // the vertical resolution of a single channel
735                                 int height = h * pcm_magnitude / channels / 2 / 32768;
736                         // Determine the starting y coordinate - left top, right bottom
737                         int displacement = h * (j * 2 + 1) / channels / 2 - ( *pcm < 0 ? 0 : height );
738                         // Position buffer pointer using y coordinate, stride, and x coordinate
739                         unsigned char *p = bitmap + i / skip + displacement * w;
740
741                         // Draw vertical line
742                         for ( k = 0; k < height + 1; k++ )
743                                 if ( *pcm < 0 )
744                                         p[ w * k ] = ( k == 0 ) ? 0xFF : p[ w * k ] + gray;
745                                 else
746                                         p[ w * k ] = ( k == height ) ? 0xFF : p[ w * k ] + gray;
747                 }
748         }
749
750         return bitmap;
751 }
752
753 /** Get the end service that produced self frame.
754  *
755  * This fetches the first producer of the frame and not any producers that
756  * encapsulate it.
757  *
758  * \public \memberof mlt_frame_s
759  * \param self a frame
760  * \return a producer
761  */
762
763 mlt_producer mlt_frame_get_original_producer( mlt_frame self )
764 {
765         if ( self != NULL )
766                 return mlt_properties_get_data( MLT_FRAME_PROPERTIES( self ), "_producer", NULL );
767         return NULL;
768 }
769
770 /** Destroy the frame.
771  *
772  * \public \memberof mlt_frame_s
773  * \param self a frame
774  */
775
776 void mlt_frame_close( mlt_frame self )
777 {
778         if ( self != NULL && mlt_properties_dec_ref( MLT_FRAME_PROPERTIES( self ) ) <= 0 )
779         {
780                 mlt_deque_close( self->stack_image );
781                 mlt_deque_close( self->stack_audio );
782                 while( mlt_deque_peek_back( self->stack_service ) )
783                         mlt_service_close( mlt_deque_pop_back( self->stack_service ) );
784                 mlt_deque_close( self->stack_service );
785                 mlt_properties_close( &self->parent );
786                 free( self );
787         }
788 }
789
790 /***** convenience functions *****/
791
792 /** Determine the number of samples that belong in a frame at a time position.
793  *
794  * \public \memberof mlt_frame_s
795  * \param fps the frame rate
796  * \param frequency the sample rate
797  * \param position the time position
798  * \return the number of samples per channel
799  */
800
801 int mlt_sample_calculator( float fps, int frequency, int64_t position )
802 {
803         /* Compute the cumulative number of samples until the start of this frame and the
804         cumulative number of samples until the start of the next frame. Round each to the
805         nearest integer and take the difference to determine the number of samples in
806         this frame.
807
808         This approach should prevent rounding errors that can accumulate over a large number
809         of frames causing A/V sync problems. */
810         return mlt_sample_calculator_to_now( fps, frequency, position + 1 )
811                  - mlt_sample_calculator_to_now( fps, frequency, position );
812 }
813
814 /** Determine the number of samples that belong before a time position.
815  *
816  * \public \memberof mlt_frame_s
817  * \param fps the frame rate
818  * \param frequency the sample rate
819  * \param position the time position
820  * \return the number of samples per channel
821  * \bug Will this break when mlt_position is converted to double?
822  */
823
824 int64_t mlt_sample_calculator_to_now( float fps, int frequency, int64_t position )
825 {
826         int64_t samples = 0;
827
828         if ( fps )
829         {
830                 samples = (int64_t)( (double) position * (double) frequency / (double) fps +
831                         ( position < 0 ? -0.5 : 0.5 ) );
832         }
833
834         return samples;
835 }
836
837 void mlt_frame_write_ppm( mlt_frame frame )
838 {
839         int width;
840         int height;
841         mlt_image_format format = mlt_image_rgb24;
842         uint8_t *image;
843         
844         if ( mlt_frame_get_image( frame, &image, &format, &width, &height, 0 ) == 0 )
845         {
846                 FILE *file;
847                 char filename[16];
848                 
849                 sprintf( filename, "frame-%05d.ppm", mlt_frame_get_position( frame ) );
850                 file = fopen( filename, "wb" );
851                 if ( !file )
852                         return;
853                 fprintf( file, "P6\n%d %d\n255\n", width, height);
854                 fwrite( image, width * height * 3, 1, file );
855                 fclose( file );
856         }
857 }
858
859 /** Get or create a properties object unique to this service instance.
860  *
861  * Use this function to hold a service's processing parameters for this
862  * particular frame. Set the parameters in the service's process function.
863  * Then, get the parameters in the function it pushes to the frame's audio
864  * or image stack. This makes the service more parallel by reducing race
865  * conditions and less sensitive to multiple instances (by not setting a
866  * non-unique property on the frame). Creation and destruction of the
867  * properties object is handled automatically.
868  *
869  * \public \memberof mlt_frame_s
870  * \param self a frame
871  * \param service a service
872  * \return a properties object
873  */
874
875 mlt_properties mlt_frame_unique_properties( mlt_frame self, mlt_service service )
876 {
877         mlt_properties frame_props = MLT_FRAME_PROPERTIES( self );
878         mlt_properties service_props = MLT_SERVICE_PROPERTIES( service );
879         char *unique = mlt_properties_get( service_props, "_unique_id" );
880         mlt_properties instance_props = mlt_properties_get_data( frame_props, unique, NULL );
881         
882         if ( !instance_props )
883         {
884                 instance_props = mlt_properties_new();
885                 mlt_properties_set_data( frame_props, unique, instance_props, 0, (mlt_destructor) mlt_properties_close, NULL );
886         }
887
888         return instance_props;
889 }