]> git.sesse.net Git - mlt/blob - src/framework/mlt_frame.c
Add mlt_frame_set_image and mlt_frame_set_alpha.
[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 image associated to the frame.
389  *
390  * You should express the desired format, width, and height as inputs. As long
391  * as the loader producer was used to generate this or the imageconvert filter
392  * was attached, then you will get the image back in the format you desire.
393  * However, you do not always get the width and height you request depending
394  * on properties and filters. You do not need to supply a pre-allocated
395  * buffer, but you should always supply the desired image format.
396  *
397  * \public \memberof mlt_frame_s
398  * \param self a frame
399  * \param[out] buffer an image buffer
400  * \param[in,out] format the image format
401  * \param[in,out] width the horizontal size in pixels
402  * \param[in,out] height the vertical size in pixels
403  * \param writable whether or not you will need to be able to write to the memory returned in \p buffer
404  * \return true if error
405  * \todo Better describe the width and height as inputs.
406  */
407
408 int mlt_frame_get_image( mlt_frame self, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
409 {
410         mlt_properties properties = MLT_FRAME_PROPERTIES( self );
411         mlt_get_image get_image = mlt_frame_pop_get_image( self );
412         mlt_producer producer = mlt_properties_get_data( properties, "test_card_producer", NULL );
413         mlt_image_format requested_format = *format;
414         int error = 0;
415
416         if ( get_image )
417         {
418                 mlt_properties_set_int( properties, "image_count", mlt_properties_get_int( properties, "image_count" ) - 1 );
419                 error = get_image( self, buffer, format, width, height, writable );
420                 if ( !error && *buffer )
421                 {
422                         mlt_properties_set_int( properties, "width", *width );
423                         mlt_properties_set_int( properties, "height", *height );
424                         if ( self->convert_image && *buffer )
425                                 self->convert_image( self, buffer, format, requested_format );
426                         mlt_properties_set_int( properties, "format", *format );
427                 }
428                 else
429                 {
430                         // Cause the image to be loaded from test card or fallback (white) below.
431                         mlt_frame_get_image( self, buffer, format, width, height, writable );
432                 }
433         }
434         else if ( mlt_properties_get_data( properties, "image", NULL ) )
435         {
436                 *format = mlt_properties_get_int( properties, "format" );
437                 *buffer = mlt_properties_get_data( properties, "image", NULL );
438                 *width = mlt_properties_get_int( properties, "width" );
439                 *height = mlt_properties_get_int( properties, "height" );
440                 if ( self->convert_image && *buffer )
441                 {
442                         self->convert_image( self, buffer, format, requested_format );
443                         mlt_properties_set_int( properties, "format", *format );
444                 }
445         }
446         else if ( producer )
447         {
448                 mlt_frame test_frame = NULL;
449                 mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &test_frame, 0 );
450                 if ( test_frame )
451                 {
452                         mlt_properties test_properties = MLT_FRAME_PROPERTIES( test_frame );
453                         mlt_properties_set_double( test_properties, "consumer_aspect_ratio", mlt_properties_get_double( properties, "consumer_aspect_ratio" ) );
454                         mlt_properties_set( test_properties, "rescale.interp", mlt_properties_get( properties, "rescale.interp" ) );
455                         mlt_frame_get_image( test_frame, buffer, format, width, height, writable );
456                         mlt_properties_set_data( properties, "test_card_frame", test_frame, 0, ( mlt_destructor )mlt_frame_close, NULL );
457                         mlt_properties_set_double( properties, "aspect_ratio", mlt_frame_get_aspect_ratio( test_frame ) );
458 //                      mlt_properties_set_data( properties, "image", *buffer, *width * *height * 2, NULL, NULL );
459 //                      mlt_properties_set_int( properties, "width", *width );
460 //                      mlt_properties_set_int( properties, "height", *height );
461 //                      mlt_properties_set_int( properties, "format", *format );
462                 }
463                 else
464                 {
465                         mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL );
466                         mlt_frame_get_image( self, buffer, format, width, height, writable );
467                 }
468         }
469         else
470         {
471                 register uint8_t *p;
472                 register uint8_t *q;
473                 int size = 0;
474
475                 *width = *width == 0 ? 720 : *width;
476                 *height = *height == 0 ? 576 : *height;
477                 size = *width * *height;
478
479                 mlt_properties_set_int( properties, "format", *format );
480                 mlt_properties_set_int( properties, "width", *width );
481                 mlt_properties_set_int( properties, "height", *height );
482                 mlt_properties_set_int( properties, "aspect_ratio", 0 );
483
484                 switch( *format )
485                 {
486                         case mlt_image_none:
487                                 size = 0;
488                                 *buffer = NULL;
489                                 break;
490                         case mlt_image_rgb24:
491                                 size *= 3;
492                                 size += *width * 3;
493                                 *buffer = mlt_pool_alloc( size );
494                                 if ( *buffer )
495                                         memset( *buffer, 255, size );
496                                 break;
497                         case mlt_image_rgb24a:
498                         case mlt_image_opengl:
499                                 size *= 4;
500                                 size += *width * 4;
501                                 *buffer = mlt_pool_alloc( size );
502                                 if ( *buffer )
503                                         memset( *buffer, 255, size );
504                                 break;
505                         case mlt_image_yuv422:
506                                 size *= 2;
507                                 size += *width * 2;
508                                 *buffer = mlt_pool_alloc( size );
509                                 p = *buffer;
510                                 q = p + size;
511                                 while ( p != NULL && p != q )
512                                 {
513                                         *p ++ = 235;
514                                         *p ++ = 128;
515                                 }
516                                 break;
517                         case mlt_image_yuv420p:
518                                 size = size * 3 / 2;
519                                 *buffer = mlt_pool_alloc( size );
520                                 if ( *buffer )
521                                         memset( *buffer, 255, size );
522                                 break;
523                 }
524
525                 mlt_properties_set_data( properties, "image", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL );
526                 mlt_properties_set_int( properties, "test_image", 1 );
527         }
528
529         return error;
530 }
531
532 /** Get the alpha channel associated to the frame.
533  *
534  * \public \memberof mlt_frame_s
535  * \param self a frame
536  * \return the alpha channel
537  */
538
539 uint8_t *mlt_frame_get_alpha_mask( mlt_frame self )
540 {
541         uint8_t *alpha = NULL;
542         if ( self != NULL )
543         {
544                 if ( self->get_alpha_mask != NULL )
545                         alpha = self->get_alpha_mask( self );
546                 if ( alpha == NULL )
547                         alpha = mlt_properties_get_data( &self->parent, "alpha", NULL );
548                 if ( alpha == NULL )
549                 {
550                         int size = mlt_properties_get_int( &self->parent, "width" ) * mlt_properties_get_int( &self->parent, "height" );
551                         alpha = mlt_pool_alloc( size );
552                         memset( alpha, 255, size );
553                         mlt_properties_set_data( &self->parent, "alpha", alpha, size, mlt_pool_release, NULL );
554                 }
555         }
556         return alpha;
557 }
558
559 /** Get the short name for an audio format.
560  *
561  * You do not need to deallocate the returned string.
562  * \public \memberof mlt_frame_s
563  * \param self a frame
564  * \param format an image format enum
565  * \return a string for the name of the image format
566  */
567
568 const char * mlt_audio_format_name( mlt_audio_format format )
569 {
570         switch ( format )
571         {
572                 case mlt_audio_none:   return "none";
573                 case mlt_audio_s16:    return "s16";
574                 case mlt_audio_s32:    return "s32";
575                 case mlt_audio_float:  return "float";
576         }
577         return "invalid";
578 }
579
580 /** Get the audio associated to the frame.
581  *
582  * You should express the desired format, frequency, channels, and samples as inputs. As long
583  * as the loader producer was used to generate this or the audioconvert filter
584  * was attached, then you will get the audio back in the format you desire.
585  * However, you do not always get the channels and samples you request depending
586  * on properties and filters. You do not need to supply a pre-allocated
587  * buffer, but you should always supply the desired audio format.
588  * The audio is always in interleaved format.
589  * You should use the \p mlt_sample_calculator to determine the number of samples you want.
590  *
591  * \public \memberof mlt_frame_s
592  * \param self a frame
593  * \param[out] buffer an audio buffer
594  * \param[in,out] format the audio format
595  * \param[in,out] frequency the sample rate
596  * \param[in,out] channels
597  * \param[in,out] samples the number of samples per frame
598  * \return true if error
599  */
600
601 int mlt_frame_get_audio( mlt_frame self, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
602 {
603         mlt_get_audio get_audio = mlt_frame_pop_audio( self );
604         mlt_properties properties = MLT_FRAME_PROPERTIES( self );
605         int hide = mlt_properties_get_int( properties, "test_audio" );
606         mlt_audio_format requested_format = *format;
607
608         if ( hide == 0 && get_audio != NULL )
609         {
610                 get_audio( self, buffer, format, frequency, channels, samples );
611                 mlt_properties_set_int( properties, "audio_frequency", *frequency );
612                 mlt_properties_set_int( properties, "audio_channels", *channels );
613                 mlt_properties_set_int( properties, "audio_samples", *samples );
614                 mlt_properties_set_int( properties, "audio_format", *format );
615                 if ( self->convert_audio )
616                         self->convert_audio( self, buffer, format, requested_format );
617         }
618         else if ( mlt_properties_get_data( properties, "audio", NULL ) )
619         {
620                 *buffer = mlt_properties_get_data( properties, "audio", NULL );
621                 *format = mlt_properties_get_int( properties, "audio_format" );
622                 *frequency = mlt_properties_get_int( properties, "audio_frequency" );
623                 *channels = mlt_properties_get_int( properties, "audio_channels" );
624                 *samples = mlt_properties_get_int( properties, "audio_samples" );
625                 if ( self->convert_audio )
626                         self->convert_audio( self, buffer, format, requested_format );
627         }
628         else
629         {
630                 int size = 0;
631                 *samples = *samples <= 0 ? 1920 : *samples;
632                 *channels = *channels <= 0 ? 2 : *channels;
633                 *frequency = *frequency <= 0 ? 48000 : *frequency;
634                 mlt_properties_set_int( properties, "audio_frequency", *frequency );
635                 mlt_properties_set_int( properties, "audio_channels", *channels );
636                 mlt_properties_set_int( properties, "audio_samples", *samples );
637                 mlt_properties_set_int( properties, "audio_format", *format );
638
639                 switch( *format )
640                 {
641                         case mlt_image_none:
642                                 size = 0;
643                                 *buffer = NULL;
644                                 break;
645                         case mlt_audio_s16:
646                                 size = *samples * *channels * sizeof( int16_t );
647                                 break;
648                         case mlt_audio_s32:
649                                 size = *samples * *channels * sizeof( int32_t );
650                                 break;
651                         case mlt_audio_float:
652                                 size = *samples * *channels * sizeof( float );
653                                 break;
654                 }
655                 if ( size )
656                         *buffer = mlt_pool_alloc( size );
657                 if ( *buffer )
658                         memset( *buffer, 0, size );
659                 mlt_properties_set_data( properties, "audio", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL );
660                 mlt_properties_set_int( properties, "test_audio", 1 );
661         }
662
663         // TODO: This does not belong here
664         if ( *format == mlt_audio_s16 && mlt_properties_get( properties, "meta.volume" ) )
665         {
666                 double value = mlt_properties_get_double( properties, "meta.volume" );
667
668                 if ( value == 0.0 )
669                 {
670                         memset( *buffer, 0, *samples * *channels * 2 );
671                 }
672                 else if ( value != 1.0 )
673                 {
674                         int total = *samples * *channels;
675                         int16_t *p = *buffer;
676                         while ( total -- )
677                         {
678                                 *p = *p * value;
679                                 p ++;
680                         }
681                 }
682
683                 mlt_properties_set( properties, "meta.volume", NULL );
684         }
685
686         return 0;
687 }
688
689 /** Set the audio on a frame.
690  *
691  * \public \memberof mlt_frame_s
692  * \param self a frame
693  * \param buffer an buffer containing audio samples
694  * \param format the format of the audio in the \p buffer
695  * \param size the total size of the buffer (optional)
696  * \param destructor a function that releases or deallocates the \p buffer
697  * \return true if error
698  */
699
700 int mlt_frame_set_audio( mlt_frame self, void *buffer, mlt_audio_format format, int size, mlt_destructor destructor )
701 {
702         mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "audio_format", format );
703         return mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "audio", buffer, size, destructor, NULL );
704 }
705
706 /** Get audio on a frame as a waveform image.
707  *
708  * This generates an 8-bit grayscale image representation of the audio in a
709  * frame. Currently, this only really works for 2 channels.
710  * This allocates the bitmap using mlt_pool so you should release the return
711  * value with \p mlt_pool_release.
712  *
713  * \public \memberof mlt_frame_s
714  * \param self a frame
715  * \param w the width of the image
716  * \param h the height of the image to create
717  * \return a pointer to a new bitmap
718  */
719
720 unsigned char *mlt_frame_get_waveform( mlt_frame self, int w, int h )
721 {
722         int16_t *pcm = NULL;
723         mlt_properties properties = MLT_FRAME_PROPERTIES( self );
724         mlt_audio_format format = mlt_audio_s16;
725         int frequency = 16000;
726         int channels = 2;
727         mlt_producer producer = mlt_frame_get_original_producer( self );
728         double fps = mlt_producer_get_fps( mlt_producer_cut_parent( producer ) );
729         int samples = mlt_sample_calculator( fps, frequency, mlt_frame_get_position( self ) );
730
731         // Increase audio resolution proportional to requested image size
732         while ( samples < w )
733         {
734                 frequency += 16000;
735                 samples = mlt_sample_calculator( fps, frequency, mlt_frame_get_position( self ) );
736         }
737
738         // Get the pcm data
739         mlt_frame_get_audio( self, (void**)&pcm, &format, &frequency, &channels, &samples );
740
741         // Make an 8-bit buffer large enough to hold rendering
742         int size = w * h;
743         unsigned char *bitmap = ( unsigned char* )mlt_pool_alloc( size );
744         if ( bitmap != NULL )
745                 memset( bitmap, 0, size );
746         mlt_properties_set_data( properties, "waveform", bitmap, size, ( mlt_destructor )mlt_pool_release, NULL );
747
748         // Render vertical lines
749         int16_t *ubound = pcm + samples * channels;
750         int skip = samples / w;
751         skip = !skip ? 1 : skip;
752         unsigned char gray = 0xFF / skip;
753         int i, j, k;
754
755         // Iterate sample stream and along x coordinate
756         for ( i = 0; pcm < ubound; i++ )
757         {
758                 // pcm data has channels interleaved
759                 for ( j = 0; j < channels; j++, pcm++ )
760                 {
761                         // Determine sample's magnitude from 2s complement;
762                         int pcm_magnitude = *pcm < 0 ? ~(*pcm) + 1 : *pcm;
763                         // The height of a line is the ratio of the magnitude multiplied by
764                         // the vertical resolution of a single channel
765                                 int height = h * pcm_magnitude / channels / 2 / 32768;
766                         // Determine the starting y coordinate - left top, right bottom
767                         int displacement = h * (j * 2 + 1) / channels / 2 - ( *pcm < 0 ? 0 : height );
768                         // Position buffer pointer using y coordinate, stride, and x coordinate
769                         unsigned char *p = bitmap + i / skip + displacement * w;
770
771                         // Draw vertical line
772                         for ( k = 0; k < height + 1; k++ )
773                                 if ( *pcm < 0 )
774                                         p[ w * k ] = ( k == 0 ) ? 0xFF : p[ w * k ] + gray;
775                                 else
776                                         p[ w * k ] = ( k == height ) ? 0xFF : p[ w * k ] + gray;
777                 }
778         }
779
780         return bitmap;
781 }
782
783 /** Get the end service that produced self frame.
784  *
785  * This fetches the first producer of the frame and not any producers that
786  * encapsulate it.
787  *
788  * \public \memberof mlt_frame_s
789  * \param self a frame
790  * \return a producer
791  */
792
793 mlt_producer mlt_frame_get_original_producer( mlt_frame self )
794 {
795         if ( self != NULL )
796                 return mlt_properties_get_data( MLT_FRAME_PROPERTIES( self ), "_producer", NULL );
797         return NULL;
798 }
799
800 /** Destroy the frame.
801  *
802  * \public \memberof mlt_frame_s
803  * \param self a frame
804  */
805
806 void mlt_frame_close( mlt_frame self )
807 {
808         if ( self != NULL && mlt_properties_dec_ref( MLT_FRAME_PROPERTIES( self ) ) <= 0 )
809         {
810                 mlt_deque_close( self->stack_image );
811                 mlt_deque_close( self->stack_audio );
812                 while( mlt_deque_peek_back( self->stack_service ) )
813                         mlt_service_close( mlt_deque_pop_back( self->stack_service ) );
814                 mlt_deque_close( self->stack_service );
815                 mlt_properties_close( &self->parent );
816                 free( self );
817         }
818 }
819
820 /***** convenience functions *****/
821
822 /** Determine the number of samples that belong in a frame at a time position.
823  *
824  * \public \memberof mlt_frame_s
825  * \param fps the frame rate
826  * \param frequency the sample rate
827  * \param position the time position
828  * \return the number of samples per channel
829  */
830
831 int mlt_sample_calculator( float fps, int frequency, int64_t position )
832 {
833         /* Compute the cumulative number of samples until the start of this frame and the
834         cumulative number of samples until the start of the next frame. Round each to the
835         nearest integer and take the difference to determine the number of samples in
836         this frame.
837
838         This approach should prevent rounding errors that can accumulate over a large number
839         of frames causing A/V sync problems. */
840         return mlt_sample_calculator_to_now( fps, frequency, position + 1 )
841                  - mlt_sample_calculator_to_now( fps, frequency, position );
842 }
843
844 /** Determine the number of samples that belong before a time position.
845  *
846  * \public \memberof mlt_frame_s
847  * \param fps the frame rate
848  * \param frequency the sample rate
849  * \param position the time position
850  * \return the number of samples per channel
851  * \bug Will this break when mlt_position is converted to double?
852  */
853
854 int64_t mlt_sample_calculator_to_now( float fps, int frequency, int64_t position )
855 {
856         int64_t samples = 0;
857
858         if ( fps )
859         {
860                 samples = (int64_t)( (double) position * (double) frequency / (double) fps +
861                         ( position < 0 ? -0.5 : 0.5 ) );
862         }
863
864         return samples;
865 }
866
867 void mlt_frame_write_ppm( mlt_frame frame )
868 {
869         int width;
870         int height;
871         mlt_image_format format = mlt_image_rgb24;
872         uint8_t *image;
873         
874         if ( mlt_frame_get_image( frame, &image, &format, &width, &height, 0 ) == 0 )
875         {
876                 FILE *file;
877                 char filename[16];
878                 
879                 sprintf( filename, "frame-%05d.ppm", mlt_frame_get_position( frame ) );
880                 file = fopen( filename, "wb" );
881                 if ( !file )
882                         return;
883                 fprintf( file, "P6\n%d %d\n255\n", width, height);
884                 fwrite( image, width * height * 3, 1, file );
885                 fclose( file );
886         }
887 }
888
889 /** Get or create a properties object unique to this service instance.
890  *
891  * Use this function to hold a service's processing parameters for this
892  * particular frame. Set the parameters in the service's process function.
893  * Then, get the parameters in the function it pushes to the frame's audio
894  * or image stack. This makes the service more parallel by reducing race
895  * conditions and less sensitive to multiple instances (by not setting a
896  * non-unique property on the frame). Creation and destruction of the
897  * properties object is handled automatically.
898  *
899  * \public \memberof mlt_frame_s
900  * \param self a frame
901  * \param service a service
902  * \return a properties object
903  */
904
905 mlt_properties mlt_frame_unique_properties( mlt_frame self, mlt_service service )
906 {
907         mlt_properties frame_props = MLT_FRAME_PROPERTIES( self );
908         mlt_properties service_props = MLT_SERVICE_PROPERTIES( service );
909         char *unique = mlt_properties_get( service_props, "_unique_id" );
910         mlt_properties instance_props = mlt_properties_get_data( frame_props, unique, NULL );
911         
912         if ( !instance_props )
913         {
914                 instance_props = mlt_properties_new();
915                 mlt_properties_set_data( frame_props, unique, instance_props, 0, (mlt_destructor) mlt_properties_close, NULL );
916         }
917
918         return instance_props;
919 }