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