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