]> git.sesse.net Git - mlt/blob - src/framework/mlt_frame.c
set version to 0.7.8
[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 /** Set a new image on the frame.
299   *
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
306   */
307
308 int mlt_frame_set_image( mlt_frame self, uint8_t *image, int size, mlt_destructor destroy )
309 {
310         return mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "image", image, size, destroy, NULL );
311 }
312
313 /** Set a new alpha channel on the frame.
314   *
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
321   */
322
323 int mlt_frame_set_alpha( mlt_frame self, uint8_t *alpha, int size, mlt_destructor destroy )
324 {
325         return mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "alpha", alpha, size, destroy, NULL );
326 }
327
328 /** Replace image stack with the information provided.
329  *
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).
333  *
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.
337  *
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
341  * first).
342  *
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...
345  *
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
352  */
353
354 void mlt_frame_replace_image( mlt_frame self, uint8_t *image, mlt_image_format format, int width, int height )
355 {
356         // Remove all items from the stack
357         while( mlt_deque_pop_back( self->stack_image ) ) ;
358
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;
365 }
366
367 /** Get the short name for an image format.
368  *
369  * \public \memberof mlt_frame_s
370  * \param format the image format
371  * \return a string
372  */
373
374 const char * mlt_image_format_name( mlt_image_format format )
375 {
376         switch ( format )
377         {
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";
384         }
385         return "invalid";
386 }
387
388 /** Get the number of bytes needed for an image.
389   *
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
396   */
397 int mlt_image_format_size( mlt_image_format format, int width, int height, int *bpp )
398 {
399         height += 1;
400         switch ( format )
401         {
402                 case mlt_image_none:
403                         if ( bpp ) *bpp = 0;
404                         return 0;
405                 case mlt_image_rgb24:
406                         if ( bpp ) *bpp = 3;
407                         return width * height * 3;
408                 case mlt_image_opengl:
409                 case mlt_image_rgb24a:
410                         if ( bpp ) *bpp = 4;
411                         return width * height * 4;
412                 case mlt_image_yuv422:
413                         if ( bpp ) *bpp = 2;
414                         return width * height * 2;
415                 case mlt_image_yuv420p:
416                         if ( bpp ) *bpp = 3 / 2;
417                         return width * height * 3 / 2;
418         }
419         return 0;
420 }
421
422 /** Get the image associated to the frame.
423  *
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.
430  *
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.
440  */
441
442 int mlt_frame_get_image( mlt_frame self, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
443 {
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;
448         int error = 0;
449
450         if ( get_image )
451         {
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 )
455                 {
456                         mlt_properties_set_int( properties, "width", *width );
457                         mlt_properties_set_int( properties, "height", *height );
458                         if ( self->convert_image && *buffer && requested_format != mlt_image_none )
459                                 self->convert_image( self, buffer, format, requested_format );
460                         mlt_properties_set_int( properties, "format", *format );
461                 }
462                 else
463                 {
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 );
466                 }
467         }
468         else if ( mlt_properties_get_data( properties, "image", NULL ) )
469         {
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 && requested_format != mlt_image_none )
475                 {
476                         self->convert_image( self, buffer, format, requested_format );
477                         mlt_properties_set_int( properties, "format", *format );
478                 }
479         }
480         else if ( producer )
481         {
482                 mlt_frame test_frame = NULL;
483                 mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &test_frame, 0 );
484                 if ( test_frame )
485                 {
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 );
496                 }
497                 else
498                 {
499                         mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL );
500                         mlt_frame_get_image( self, buffer, format, width, height, writable );
501                 }
502         }
503         else
504         {
505                 register uint8_t *p;
506                 register uint8_t *q;
507                 int size = 0;
508
509                 *width = *width == 0 ? 720 : *width;
510                 *height = *height == 0 ? 576 : *height;
511                 size = *width * *height;
512
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 );
517
518                 switch( *format )
519                 {
520                         case mlt_image_none:
521                                 size = 0;
522                                 *buffer = NULL;
523                                 break;
524                         case mlt_image_rgb24:
525                                 size *= 3;
526                                 size += *width * 3;
527                                 *buffer = mlt_pool_alloc( size );
528                                 if ( *buffer )
529                                         memset( *buffer, 255, size );
530                                 break;
531                         case mlt_image_rgb24a:
532                         case mlt_image_opengl:
533                                 size *= 4;
534                                 size += *width * 4;
535                                 *buffer = mlt_pool_alloc( size );
536                                 if ( *buffer )
537                                         memset( *buffer, 255, size );
538                                 break;
539                         case mlt_image_yuv422:
540                                 size *= 2;
541                                 size += *width * 2;
542                                 *buffer = mlt_pool_alloc( size );
543                                 p = *buffer;
544                                 q = p + size;
545                                 while ( p != NULL && p != q )
546                                 {
547                                         *p ++ = 235;
548                                         *p ++ = 128;
549                                 }
550                                 break;
551                         case mlt_image_yuv420p:
552                                 size = size * 3 / 2;
553                                 *buffer = mlt_pool_alloc( size );
554                                 if ( *buffer )
555                                         memset( *buffer, 255, size );
556                                 break;
557                 }
558
559                 mlt_properties_set_data( properties, "image", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL );
560                 mlt_properties_set_int( properties, "test_image", 1 );
561         }
562
563         return error;
564 }
565
566 /** Get the alpha channel associated to the frame.
567  *
568  * \public \memberof mlt_frame_s
569  * \param self a frame
570  * \return the alpha channel
571  */
572
573 uint8_t *mlt_frame_get_alpha_mask( mlt_frame self )
574 {
575         uint8_t *alpha = NULL;
576         if ( self != NULL )
577         {
578                 if ( self->get_alpha_mask != NULL )
579                         alpha = self->get_alpha_mask( self );
580                 if ( alpha == NULL )
581                         alpha = mlt_properties_get_data( &self->parent, "alpha", NULL );
582                 if ( alpha == NULL )
583                 {
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 );
588                 }
589         }
590         return alpha;
591 }
592
593 /** Get the short name for an audio format.
594  *
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
599  */
600
601 const char * mlt_audio_format_name( mlt_audio_format format )
602 {
603         switch ( format )
604         {
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_s32le:  return "s32le";
609                 case mlt_audio_float:  return "float";
610                 case mlt_audio_f32le:  return "f32le";
611         }
612         return "invalid";
613 }
614
615 /** Get the amount of bytes needed for a block of audio.
616   *
617   * \public \memberof mlt_frame_s
618   * \param format an audio format enum
619   * \param samples the number of samples per channel
620   * \param channels the number of channels
621   * \return the number of bytes
622   */
623
624 int mlt_audio_format_size( mlt_audio_format format, int samples, int channels )
625 {
626         switch ( format )
627         {
628                 case mlt_audio_none:   return 0;
629                 case mlt_audio_s16:    return samples * channels * sizeof( int16_t );
630                 case mlt_audio_s32le:
631                 case mlt_audio_s32:    return samples * channels * sizeof( int32_t );
632                 case mlt_audio_f32le:
633                 case mlt_audio_float:  return samples * channels * sizeof( float );
634         }
635         return 0;
636 }
637
638 /** Get the audio associated to the frame.
639  *
640  * You should express the desired format, frequency, channels, and samples as inputs. As long
641  * as the loader producer was used to generate this or the audioconvert filter
642  * was attached, then you will get the audio back in the format you desire.
643  * However, you do not always get the channels and samples you request depending
644  * on properties and filters. You do not need to supply a pre-allocated
645  * buffer, but you should always supply the desired audio format.
646  * The audio is always in interleaved format.
647  * You should use the \p mlt_sample_calculator to determine the number of samples you want.
648  *
649  * \public \memberof mlt_frame_s
650  * \param self a frame
651  * \param[out] buffer an audio buffer
652  * \param[in,out] format the audio format
653  * \param[in,out] frequency the sample rate
654  * \param[in,out] channels
655  * \param[in,out] samples the number of samples per frame
656  * \return true if error
657  */
658
659 int mlt_frame_get_audio( mlt_frame self, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
660 {
661         mlt_get_audio get_audio = mlt_frame_pop_audio( self );
662         mlt_properties properties = MLT_FRAME_PROPERTIES( self );
663         int hide = mlt_properties_get_int( properties, "test_audio" );
664         mlt_audio_format requested_format = *format;
665
666         if ( hide == 0 && get_audio != NULL )
667         {
668                 get_audio( self, buffer, format, frequency, channels, samples );
669                 mlt_properties_set_int( properties, "audio_frequency", *frequency );
670                 mlt_properties_set_int( properties, "audio_channels", *channels );
671                 mlt_properties_set_int( properties, "audio_samples", *samples );
672                 mlt_properties_set_int( properties, "audio_format", *format );
673                 if ( self->convert_audio && *buffer && requested_format != mlt_audio_none )
674                         self->convert_audio( self, buffer, format, requested_format );
675         }
676         else if ( mlt_properties_get_data( properties, "audio", NULL ) )
677         {
678                 *buffer = mlt_properties_get_data( properties, "audio", NULL );
679                 *format = mlt_properties_get_int( properties, "audio_format" );
680                 *frequency = mlt_properties_get_int( properties, "audio_frequency" );
681                 *channels = mlt_properties_get_int( properties, "audio_channels" );
682                 *samples = mlt_properties_get_int( properties, "audio_samples" );
683                 if ( self->convert_audio && *buffer && requested_format != mlt_audio_none )
684                         self->convert_audio( self, buffer, format, requested_format );
685         }
686         else
687         {
688                 int size = 0;
689                 *samples = *samples <= 0 ? 1920 : *samples;
690                 *channels = *channels <= 0 ? 2 : *channels;
691                 *frequency = *frequency <= 0 ? 48000 : *frequency;
692                 mlt_properties_set_int( properties, "audio_frequency", *frequency );
693                 mlt_properties_set_int( properties, "audio_channels", *channels );
694                 mlt_properties_set_int( properties, "audio_samples", *samples );
695                 mlt_properties_set_int( properties, "audio_format", *format );
696
697                 switch( *format )
698                 {
699                         case mlt_image_none:
700                                 size = 0;
701                                 *buffer = NULL;
702                                 break;
703                         case mlt_audio_s16:
704                                 size = *samples * *channels * sizeof( int16_t );
705                                 break;
706                         case mlt_audio_s32:
707                                 size = *samples * *channels * sizeof( int32_t );
708                                 break;
709                         case mlt_audio_float:
710                                 size = *samples * *channels * sizeof( float );
711                                 break;
712                         default:
713                                 break;
714                 }
715                 if ( size )
716                         *buffer = mlt_pool_alloc( size );
717                 if ( *buffer )
718                         memset( *buffer, 0, size );
719                 mlt_properties_set_data( properties, "audio", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL );
720                 mlt_properties_set_int( properties, "test_audio", 1 );
721         }
722
723         // TODO: This does not belong here
724         if ( *format == mlt_audio_s16 && mlt_properties_get( properties, "meta.volume" ) )
725         {
726                 double value = mlt_properties_get_double( properties, "meta.volume" );
727
728                 if ( value == 0.0 )
729                 {
730                         memset( *buffer, 0, *samples * *channels * 2 );
731                 }
732                 else if ( value != 1.0 )
733                 {
734                         int total = *samples * *channels;
735                         int16_t *p = *buffer;
736                         while ( total -- )
737                         {
738                                 *p = *p * value;
739                                 p ++;
740                         }
741                 }
742
743                 mlt_properties_set( properties, "meta.volume", NULL );
744         }
745
746         return 0;
747 }
748
749 /** Set the audio on a frame.
750  *
751  * \public \memberof mlt_frame_s
752  * \param self a frame
753  * \param buffer an buffer containing audio samples
754  * \param format the format of the audio in the \p buffer
755  * \param size the total size of the buffer (optional)
756  * \param destructor a function that releases or deallocates the \p buffer
757  * \return true if error
758  */
759
760 int mlt_frame_set_audio( mlt_frame self, void *buffer, mlt_audio_format format, int size, mlt_destructor destructor )
761 {
762         mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "audio_format", format );
763         return mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "audio", buffer, size, destructor, NULL );
764 }
765
766 /** Get audio on a frame as a waveform image.
767  *
768  * This generates an 8-bit grayscale image representation of the audio in a
769  * frame. Currently, this only really works for 2 channels.
770  * This allocates the bitmap using mlt_pool so you should release the return
771  * value with \p mlt_pool_release.
772  *
773  * \public \memberof mlt_frame_s
774  * \param self a frame
775  * \param w the width of the image
776  * \param h the height of the image to create
777  * \return a pointer to a new bitmap
778  */
779
780 unsigned char *mlt_frame_get_waveform( mlt_frame self, int w, int h )
781 {
782         int16_t *pcm = NULL;
783         mlt_properties properties = MLT_FRAME_PROPERTIES( self );
784         mlt_audio_format format = mlt_audio_s16;
785         int frequency = 16000;
786         int channels = 2;
787         mlt_producer producer = mlt_frame_get_original_producer( self );
788         double fps = mlt_producer_get_fps( mlt_producer_cut_parent( producer ) );
789         int samples = mlt_sample_calculator( fps, frequency, mlt_frame_get_position( self ) );
790
791         // Increase audio resolution proportional to requested image size
792         while ( samples < w )
793         {
794                 frequency += 16000;
795                 samples = mlt_sample_calculator( fps, frequency, mlt_frame_get_position( self ) );
796         }
797
798         // Get the pcm data
799         mlt_frame_get_audio( self, (void**)&pcm, &format, &frequency, &channels, &samples );
800
801         // Make an 8-bit buffer large enough to hold rendering
802         int size = w * h;
803         unsigned char *bitmap = ( unsigned char* )mlt_pool_alloc( size );
804         if ( bitmap != NULL )
805                 memset( bitmap, 0, size );
806         mlt_properties_set_data( properties, "waveform", bitmap, size, ( mlt_destructor )mlt_pool_release, NULL );
807
808         // Render vertical lines
809         int16_t *ubound = pcm + samples * channels;
810         int skip = samples / w;
811         skip = !skip ? 1 : skip;
812         unsigned char gray = 0xFF / skip;
813         int i, j, k;
814
815         // Iterate sample stream and along x coordinate
816         for ( i = 0; pcm < ubound; i++ )
817         {
818                 // pcm data has channels interleaved
819                 for ( j = 0; j < channels; j++, pcm++ )
820                 {
821                         // Determine sample's magnitude from 2s complement;
822                         int pcm_magnitude = *pcm < 0 ? ~(*pcm) + 1 : *pcm;
823                         // The height of a line is the ratio of the magnitude multiplied by
824                         // the vertical resolution of a single channel
825                                 int height = h * pcm_magnitude / channels / 2 / 32768;
826                         // Determine the starting y coordinate - left top, right bottom
827                         int displacement = h * (j * 2 + 1) / channels / 2 - ( *pcm < 0 ? 0 : height );
828                         // Position buffer pointer using y coordinate, stride, and x coordinate
829                         unsigned char *p = bitmap + i / skip + displacement * w;
830
831                         // Draw vertical line
832                         for ( k = 0; k < height + 1; k++ )
833                                 if ( *pcm < 0 )
834                                         p[ w * k ] = ( k == 0 ) ? 0xFF : p[ w * k ] + gray;
835                                 else
836                                         p[ w * k ] = ( k == height ) ? 0xFF : p[ w * k ] + gray;
837                 }
838         }
839
840         return bitmap;
841 }
842
843 /** Get the end service that produced self frame.
844  *
845  * This fetches the first producer of the frame and not any producers that
846  * encapsulate it.
847  *
848  * \public \memberof mlt_frame_s
849  * \param self a frame
850  * \return a producer
851  */
852
853 mlt_producer mlt_frame_get_original_producer( mlt_frame self )
854 {
855         if ( self != NULL )
856                 return mlt_properties_get_data( MLT_FRAME_PROPERTIES( self ), "_producer", NULL );
857         return NULL;
858 }
859
860 /** Destroy the frame.
861  *
862  * \public \memberof mlt_frame_s
863  * \param self a frame
864  */
865
866 void mlt_frame_close( mlt_frame self )
867 {
868         if ( self != NULL && mlt_properties_dec_ref( MLT_FRAME_PROPERTIES( self ) ) <= 0 )
869         {
870                 mlt_deque_close( self->stack_image );
871                 mlt_deque_close( self->stack_audio );
872                 while( mlt_deque_peek_back( self->stack_service ) )
873                         mlt_service_close( mlt_deque_pop_back( self->stack_service ) );
874                 mlt_deque_close( self->stack_service );
875                 mlt_properties_close( &self->parent );
876                 free( self );
877         }
878 }
879
880 /***** convenience functions *****/
881
882 /** Determine the number of samples that belong in a frame at a time position.
883  *
884  * \public \memberof mlt_frame_s
885  * \param fps the frame rate
886  * \param frequency the sample rate
887  * \param position the time position
888  * \return the number of samples per channel
889  */
890
891 int mlt_sample_calculator( float fps, int frequency, int64_t position )
892 {
893         /* Compute the cumulative number of samples until the start of this frame and the
894         cumulative number of samples until the start of the next frame. Round each to the
895         nearest integer and take the difference to determine the number of samples in
896         this frame.
897
898         This approach should prevent rounding errors that can accumulate over a large number
899         of frames causing A/V sync problems. */
900         return mlt_sample_calculator_to_now( fps, frequency, position + 1 )
901                  - mlt_sample_calculator_to_now( fps, frequency, position );
902 }
903
904 /** Determine the number of samples that belong before a time position.
905  *
906  * \public \memberof mlt_frame_s
907  * \param fps the frame rate
908  * \param frequency the sample rate
909  * \param position the time position
910  * \return the number of samples per channel
911  * \bug Will this break when mlt_position is converted to double?
912  */
913
914 int64_t mlt_sample_calculator_to_now( float fps, int frequency, int64_t position )
915 {
916         int64_t samples = 0;
917
918         if ( fps )
919         {
920                 samples = (int64_t)( (double) position * (double) frequency / (double) fps +
921                         ( position < 0 ? -0.5 : 0.5 ) );
922         }
923
924         return samples;
925 }
926
927 void mlt_frame_write_ppm( mlt_frame frame )
928 {
929         int width;
930         int height;
931         mlt_image_format format = mlt_image_rgb24;
932         uint8_t *image;
933         
934         if ( mlt_frame_get_image( frame, &image, &format, &width, &height, 0 ) == 0 )
935         {
936                 FILE *file;
937                 char filename[16];
938                 
939                 sprintf( filename, "frame-%05d.ppm", mlt_frame_get_position( frame ) );
940                 file = fopen( filename, "wb" );
941                 if ( !file )
942                         return;
943                 fprintf( file, "P6\n%d %d\n255\n", width, height);
944                 fwrite( image, width * height * 3, 1, file );
945                 fclose( file );
946         }
947 }
948
949 /** Get or create a properties object unique to this service instance.
950  *
951  * Use this function to hold a service's processing parameters for this
952  * particular frame. Set the parameters in the service's process function.
953  * Then, get the parameters in the function it pushes to the frame's audio
954  * or image stack. This makes the service more parallel by reducing race
955  * conditions and less sensitive to multiple instances (by not setting a
956  * non-unique property on the frame). Creation and destruction of the
957  * properties object is handled automatically.
958  *
959  * \public \memberof mlt_frame_s
960  * \param self a frame
961  * \param service a service
962  * \return a properties object
963  */
964
965 mlt_properties mlt_frame_unique_properties( mlt_frame self, mlt_service service )
966 {
967         mlt_properties frame_props = MLT_FRAME_PROPERTIES( self );
968         mlt_properties service_props = MLT_SERVICE_PROPERTIES( service );
969         char *unique = mlt_properties_get( service_props, "_unique_id" );
970         mlt_properties instance_props = mlt_properties_get_data( frame_props, unique, NULL );
971         
972         if ( !instance_props )
973         {
974                 instance_props = mlt_properties_new();
975                 mlt_properties_set_data( frame_props, unique, instance_props, 0, (mlt_destructor) mlt_properties_close, NULL );
976         }
977
978         return instance_props;
979 }
980
981 /** Make a copy of a frame.
982  *
983  * This does not copy the get_image/get_audio processing stacks or any
984  * data properties other than the audio and image.
985  *
986  * \public \memberof mlt_frame_s
987  * \param self the frame to clone
988  * \param is_deep a boolean to indicate whether to make a deep copy of the audio
989  * and video data chunks or to make a shallow copy by pointing to the supplied frame
990  * \return a almost-complete copy of the frame
991  * \todo copy the processing deques
992  */
993
994 mlt_frame mlt_frame_clone( mlt_frame self, int is_deep )
995 {
996         mlt_frame new_frame = mlt_frame_init( NULL );
997         mlt_properties properties = MLT_FRAME_PROPERTIES( self );
998         mlt_properties new_props = MLT_FRAME_PROPERTIES( new_frame );
999         void *data, *copy;
1000         int size;
1001
1002         mlt_properties_inherit( new_props, properties );
1003         if ( is_deep )
1004         {
1005                 data = mlt_properties_get_data( properties, "audio", &size );
1006                 if ( data )
1007                 {
1008                         if ( !size )
1009                                 size = mlt_audio_format_size( mlt_properties_get_int( properties, "audio_format" ),
1010                                         mlt_properties_get_int( properties, "audio_samples" ),
1011                                         mlt_properties_get_int( properties, "audio_channels" ) );
1012                         copy = mlt_pool_alloc( size );
1013                         memcpy( copy, data, size );
1014                         mlt_properties_set_data( new_props, "audio", copy, size, mlt_pool_release, NULL );
1015                 }
1016                 data = mlt_properties_get_data( properties, "image", &size );
1017                 if ( data )
1018                 {
1019                         if ( ! size )
1020                                 size = mlt_image_format_size( mlt_properties_get_int( properties, "format" ),
1021                                         mlt_properties_get_int( properties, "width" ),
1022                                         mlt_properties_get_int( properties, "height" ), NULL );
1023                         copy = mlt_pool_alloc( size );
1024                         memcpy( copy, data, size );
1025                         mlt_properties_set_data( new_props, "image", copy, size, mlt_pool_release, NULL );
1026                 }
1027         }
1028         else
1029         {
1030                 // This frame takes a reference on the original frame since the data is a shallow copy.
1031                 mlt_properties_inc_ref( properties );
1032                 mlt_properties_set_data( new_props, "_cloned_frame", self, 0,
1033                         (mlt_destructor) mlt_frame_close, NULL );
1034
1035                 // Copy properties
1036                 data = mlt_properties_get_data( properties, "audio", &size );
1037                 mlt_properties_set_data( new_props, "audio", data, size, NULL, NULL );
1038                 data = mlt_properties_get_data( properties, "image", &size );
1039                 mlt_properties_set_data( new_props, "image", data, size, NULL, NULL );
1040         }
1041
1042         return new_frame;
1043 }