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