]> git.sesse.net Git - mlt/blob - src/framework/mlt_frame.c
westley serialises with entry in/out; full field, aspect, and colour space normalisat...
[mlt] / src / framework / mlt_frame.c
1 /*
2  * mlt_frame.c -- interface for all frame classes
3  * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
4  * Author: Charles Yates <charles.yates@pandora.be>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  */
20
21 #include "config.h"
22 #include "mlt_frame.h"
23 #include "mlt_producer.h"
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 /** Constructor for a frame.
29 */
30
31 mlt_frame mlt_frame_init( )
32 {
33         // Allocate a frame
34         mlt_frame this = calloc( sizeof( struct mlt_frame_s ), 1 );
35
36         if ( this != NULL )
37         {
38                 // Initialise the properties
39                 mlt_properties properties = &this->parent;
40                 mlt_properties_init( properties, this );
41
42                 // Set default properties on the frame
43                 mlt_properties_set_position( properties, "_position", 0.0 );
44                 mlt_properties_set_data( properties, "image", NULL, 0, NULL, NULL );
45                 mlt_properties_set_int( properties, "width", 720 );
46                 mlt_properties_set_int( properties, "height", 576 );
47                 mlt_properties_set_double( properties, "aspect_ratio", 4.0 / 3.0 );
48                 mlt_properties_set_data( properties, "audio", NULL, 0, NULL, NULL );
49                 mlt_properties_set_data( properties, "alpha", NULL, 0, NULL, NULL );
50         }
51         return this;
52 }
53
54 /** Fetch the frames properties.
55 */
56
57 mlt_properties mlt_frame_properties( mlt_frame this )
58 {
59         return &this->parent;
60 }
61
62 /** Check if we have a way to derive something other than a test card.
63 */
64
65 int mlt_frame_is_test_card( mlt_frame this )
66 {
67         return mlt_properties_get_int( mlt_frame_properties( this ), "test_image" );
68 }
69
70 /** Check if we have a way to derive something than test audio.
71 */
72
73 int mlt_frame_is_test_audio( mlt_frame this )
74 {
75         return this->get_audio == NULL || mlt_properties_get_int( mlt_frame_properties( this ), "test_audio" );
76 }
77
78 /** Get the aspect ratio of the frame.
79 */
80
81 double mlt_frame_get_aspect_ratio( mlt_frame this )
82 {
83         return mlt_properties_get_double( mlt_frame_properties( this ), "aspect_ratio" );
84 }
85
86 /** Set the aspect ratio of the frame.
87 */
88
89 int mlt_frame_set_aspect_ratio( mlt_frame this, double value )
90 {
91         return mlt_properties_set_double( mlt_frame_properties( this ), "aspect_ratio", value );
92 }
93
94 /** Get the position of this frame.
95 */
96
97 mlt_position mlt_frame_get_position( mlt_frame this )
98 {
99         return mlt_properties_get_position( mlt_frame_properties( this ), "_position" );
100 }
101
102 /** Set the position of this frame.
103 */
104
105 int mlt_frame_set_position( mlt_frame this, mlt_position value )
106 {
107         return mlt_properties_set_position( mlt_frame_properties( this ), "_position", value );
108 }
109
110 /** Stack a get_image callback.
111 */
112
113 int mlt_frame_push_get_image( mlt_frame this, mlt_get_image get_image )
114 {
115         int ret = this->stack_get_image_size >= 10;
116         if ( ret == 0 )
117                 this->stack_get_image[ this->stack_get_image_size ++ ] = get_image;
118         return ret;
119 }
120
121 /** Pop a get_image callback.
122 */
123
124 mlt_get_image mlt_frame_pop_get_image( mlt_frame this )
125 {
126         mlt_get_image result = NULL;
127         if ( this->stack_get_image_size > 0 )
128                 result = this->stack_get_image[ -- this->stack_get_image_size ];
129         return result;
130 }
131
132 /** Push a frame.
133 */
134
135 int mlt_frame_push_frame( mlt_frame this, mlt_frame that )
136 {
137         int ret = this->stack_frame_size >= 10;
138         if ( ret == 0 )
139                 this->stack_frame[ this->stack_frame_size ++ ] = that;
140         return ret;
141 }
142
143 /** Pop a frame.
144 */
145
146 mlt_frame mlt_frame_pop_frame( mlt_frame this )
147 {
148         mlt_frame result = NULL;
149         if ( this->stack_frame_size > 0 )
150                 result = this->stack_frame[ -- this->stack_frame_size ];
151         return result;
152 }
153
154 int mlt_frame_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
155 {
156         mlt_properties properties = mlt_frame_properties( this );
157         mlt_get_image get_image = mlt_frame_pop_get_image( this );
158         mlt_producer producer = mlt_properties_get_data( properties, "test_card_producer", NULL );
159         
160         if ( get_image != NULL )
161         {
162                 return get_image( this, buffer, format, width, height, writable );
163         }
164         else if ( mlt_properties_get_data( properties, "image", NULL ) != NULL )
165         {
166                 *format = mlt_image_yuv422;
167                 *buffer = mlt_properties_get_data( properties, "image", NULL );
168                 *width = mlt_properties_get_int( properties, "width" );
169                 *height = mlt_properties_get_int( properties, "height" );
170         }
171         else if ( producer != NULL )
172         {
173                 mlt_frame test_frame = NULL;
174                 mlt_service_get_frame( mlt_producer_service( producer ), &test_frame, 0 );
175                 if ( test_frame != NULL )
176                 {
177                         mlt_frame_get_image( test_frame, buffer, format, width, height, writable );
178                         mlt_properties_inherit( mlt_frame_properties( this ), mlt_frame_properties( test_frame ) );
179                         mlt_properties_set_data( properties, "test_card_frame", test_frame, 0, ( mlt_destructor )mlt_frame_close, NULL );
180
181                         mlt_properties_set_data( properties, "image", *buffer, *width * *height * 2, NULL, NULL );
182                         mlt_properties_set_int( properties, "width", *width );
183                         mlt_properties_set_int( properties, "height", *height );
184                 }
185                 else
186                 {
187                         mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL );
188                         mlt_frame_get_image( this, buffer, format, width, height, writable );
189                 }
190         }
191         else
192         {
193                 uint8_t *p;
194                 uint8_t *q;
195                 int size = 0;
196
197                 *width = *width == 0 ? 720 : *width;
198                 *height = *height == 0 ? 576 : *height;
199                 size = *width * *height;
200
201                 mlt_properties_set_int( properties, "width", *width );
202                 mlt_properties_set_int( properties, "height", *height );
203
204                 switch( *format )
205                 {
206                         case mlt_image_none:
207                                 size = 0;
208                                 *buffer = NULL;
209                                 break;
210                         case mlt_image_rgb24:
211                                 // IRRIGATE ME
212                                 size *= 3;
213                                 size += *width * 3;
214                                 *buffer = malloc( size );
215                                 if ( *buffer )
216                                         memset( *buffer, 255, size );
217                                 break;
218                         case mlt_image_rgb24a:
219                                 // IRRIGATE ME
220                                 size *= 4;
221                                 size += *width * 4;
222                                 *buffer = malloc( size );
223                                 if ( *buffer )
224                                         memset( *buffer, 255, size );
225                                 break;
226                         case mlt_image_yuv422:
227                                 // IRRIGATE ME
228                                 size *= 2;
229                                 size += *width * 2;
230                                 *buffer = malloc( size );
231                                 p = *buffer;
232                                 q = p + size;
233                                 while ( p != NULL && p != q )
234                                 {
235                                         *p ++ = 255;
236                                         *p ++ = 128;
237                                 }
238                                 break;
239                         case mlt_image_yuv420p:
240                                 size = size * 3 / 2;
241                                 *buffer = malloc( size );
242                                         if ( *buffer )
243                                         memset( *buffer, 255, size );
244                                 break;
245                 }
246
247                 mlt_properties_set_data( properties, "image", *buffer, size, free, NULL );
248                 mlt_properties_set_int( properties, "test_image", 1 );
249         }
250
251         return 0;
252 }
253
254 uint8_t *mlt_frame_get_alpha_mask( mlt_frame this )
255 {
256         if ( this->get_alpha_mask != NULL )
257                 return this->get_alpha_mask( this );
258         return NULL;
259 }
260
261 int mlt_frame_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
262 {
263         mlt_properties properties = mlt_frame_properties( this );
264
265         if ( this->get_audio != NULL )
266         {
267                 return this->get_audio( this, buffer, format, frequency, channels, samples );
268         }
269         else
270         {
271                 int size = 0;
272                 *samples = *samples <= 0 ? 1920 : *samples;
273                 *channels = *channels <= 0 ? 2 : *channels;
274                 *frequency = *frequency <= 0 ? 48000 : *frequency;
275                 size = *samples * *channels * sizeof( int16_t );
276                 *buffer = malloc( size );
277                 if ( *buffer != NULL )
278                         memset( *buffer, 0, size );
279                 mlt_properties_set_data( properties, "audio", *buffer, size, free, NULL );
280                 mlt_properties_set_int( properties, "test_audio", 1 );
281         }
282         return 0;
283 }
284
285 void mlt_frame_close( mlt_frame this )
286 {
287         mlt_properties_close( &this->parent );
288         free( this );
289 }
290
291 /***** convenience functions *****/
292 #define RGB2YUV(r, g, b, y, u, v)\
293   y = (306*r + 601*g + 117*b)  >> 10;\
294   u = ((-172*r - 340*g + 512*b) >> 10)  + 128;\
295   v = ((512*r - 429*g - 83*b) >> 10) + 128;\
296   y = y < 0 ? 0 : y;\
297   u = u < 0 ? 0 : u;\
298   v = v < 0 ? 0 : v;\
299   y = y > 255 ? 255 : y;\
300   u = u > 255 ? 255 : u;\
301   v = v > 255 ? 255 : v
302
303 int mlt_convert_rgb24a_to_yuv422( uint8_t *rgba, int width, int height, int stride, uint8_t *yuv, uint8_t *alpha )
304 {
305         int ret = 0;
306         register int y0, y1, u0, u1, v0, v1;
307         register int r, g, b;
308         register uint8_t *d = yuv;
309         register int i, j;
310
311         for ( i = 0; i < height; i++ )
312         {
313                 register uint8_t *s = rgba + ( stride * i );
314                 for ( j = 0; j < ( width / 2 ); j++ )
315                 {
316                         r = *s++;
317                         g = *s++;
318                         b = *s++;
319                         *alpha++ = *s++;
320                         RGB2YUV (r, g, b, y0, u0 , v0);
321                         r = *s++;
322                         g = *s++;
323                         b = *s++;
324                         *alpha++ = *s++;
325                         RGB2YUV (r, g, b, y1, u1 , v1);
326                         *d++ = y0;
327                         *d++ = (u0+u1) >> 1;
328                         *d++ = y1;
329                         *d++ = (v0+v1) >> 1;
330                 }
331                 if ( width % 2 )
332                 {
333                         r = *s++;
334                         g = *s++;
335                         b = *s++;
336                         *alpha++ = *s++;
337                         RGB2YUV (r, g, b, y0, u0 , v0);
338                         *d++ = y0;
339                         *d++ = u0;
340                 }
341         }
342         return ret;
343 }
344
345 int mlt_convert_rgb24_to_yuv422( uint8_t *rgb, int width, int height, int stride, uint8_t *yuv )
346 {
347         int ret = 0;
348         register int y0, y1, u0, u1, v0, v1;
349         register int r, g, b;
350         register uint8_t *d = yuv;
351         register int i, j;
352
353         for ( i = 0; i < height; i++ )
354         {
355                 register uint8_t *s = rgb + ( stride * i );
356                 for ( j = 0; j < ( width / 2 ); j++ )
357                 {
358                         r = *s++;
359                         g = *s++;
360                         b = *s++;
361                         RGB2YUV (r, g, b, y0, u0 , v0);
362                         r = *s++;
363                         g = *s++;
364                         b = *s++;
365                         RGB2YUV (r, g, b, y1, u1 , v1);
366                         *d++ = y0;
367                         *d++ = (u0+u1) >> 1;
368                         *d++ = y1;
369                         *d++ = (v0+v1) >> 1;
370                 }
371                 if ( width % 2 )
372                 {
373                         r = *s++;
374                         g = *s++;
375                         b = *s++;
376                         RGB2YUV (r, g, b, y0, u0 , v0);
377                         *d++ = y0;
378                         *d++ = u0;
379                 }
380         }
381         return ret;
382 }
383
384 int mlt_convert_yuv420p_to_yuv422( uint8_t *yuv420p, int width, int height, int stride, uint8_t *yuv )
385 {
386         int ret = 0;
387         register int i, j;
388
389         int half = width >> 1;
390
391         uint8_t *Y = yuv420p;
392         uint8_t *U = Y + width * height;
393         uint8_t *V = U + width * height / 4;
394
395         register uint8_t *d = yuv;
396
397         for ( i = 0; i < height; i++ )
398         {
399                 register uint8_t *u = U + ( i / 2 ) * ( half );
400                 register uint8_t *v = V + ( i / 2 ) * ( half );
401
402                 for ( j = 0; j < half; j++ )
403                 {
404                         *d ++ = *Y ++;
405                         *d ++ = *u ++;
406                         *d ++ = *Y ++;
407                         *d ++ = *v ++;
408                 }
409         }
410         return ret;
411 }
412
413 void *memfill( void *dst, void *src, int l, int elements )
414 {
415         int i = 0;
416         if ( l == 2 )
417         {
418                 uint8_t *p = dst;
419                 uint8_t *src1 = src;
420                 uint8_t *src2 = src + 1;
421                 for ( i = 0; i < elements; i ++ )
422                 {
423                         *p ++ = *src1;
424                         *p ++ = *src2;
425                 }
426                 dst = p;
427         }
428         else
429         {
430                 for ( i = 0; i < elements; i ++ )
431                         dst = memcpy( dst, src, l ) + l;
432         }
433         return dst;
434 }
435
436 void mlt_resize_yuv422( uint8_t *output, int owidth, int oheight, uint8_t *input, int iwidth, int iheight )
437 {
438         // Calculate strides
439         int istride = iwidth * 2;
440         int ostride = owidth * 2;
441
442         iwidth = iwidth - ( iwidth % 4 );
443         owidth = owidth - ( owidth % 4 );
444         iheight = iheight - ( iheight % 2 );
445         oheight = oheight - ( oheight % 2 );
446
447         // Optimisation point
448         if ( iwidth == owidth && iheight == oheight )
449                 memcpy( output, input, iheight * istride );
450
451         // Coordinates (0,0 is middle of output)
452         int y;
453
454         // Calculate ranges
455         int out_x_range = owidth / 2;
456         int out_y_range = oheight / 2;
457         int in_x_range = iwidth / 2 < out_x_range ? iwidth / 2 : out_x_range;
458         int in_y_range = iheight / 2 < out_y_range ? iheight / 2 : out_y_range;
459
460         // Output pointers
461         uint8_t *out_line = output;
462         uint8_t *out_ptr = out_line;
463
464         // Calculate a middle and possibly invalid pointer in the input
465         uint8_t *in_middle = input + istride * ( iheight / 2 ) + ( iwidth / 2 ) * 2;
466         int in_line = - in_y_range * istride - in_x_range * 2;
467
468         uint8_t black[ 2 ] = { 16, 128 };
469
470         // Loop for the entirety of our output height.
471         for ( y = - out_y_range; y < out_y_range ; y ++ )
472         {
473         // Start at the beginning of the line
474         out_ptr = out_line;
475
476                 if ( abs( y ) < iheight / 2 )
477                 {
478                         // Fill the outer part with black
479                         out_ptr = memfill( out_ptr, black, 2, out_x_range - in_x_range );
480
481                 // We're in the input range for this row.
482                         memcpy( out_ptr, in_middle + in_line, 2 * iwidth );
483                         out_ptr += 2 * iwidth;
484
485                         // Fill the outer part with black
486                         out_ptr = memfill( out_ptr, black, 2, out_x_range - in_x_range );
487
488                 // Move to next input line
489                 in_line += istride;
490                 }
491                 else
492                 {
493                         // Fill whole line with black
494                         out_ptr = memfill( out_ptr, black, 2, owidth );
495                 }
496
497         // Move to next output line
498         out_line += ostride;
499         }
500 }
501
502 /** A resizing function for yuv422 frames - this does not rescale, but simply
503         resizes. It assumes yuv422 images available on the frame so use with care.
504 */
505
506 uint8_t *mlt_frame_resize_yuv422( mlt_frame this, int owidth, int oheight )
507 {
508         // Get properties
509         mlt_properties properties = mlt_frame_properties( this );
510
511         // Get the input image, width and height
512         uint8_t *input = mlt_properties_get_data( properties, "image", NULL );
513         int iwidth = mlt_properties_get_int( properties, "width" );
514         int iheight = mlt_properties_get_int( properties, "height" );
515
516         // If width and height are correct, don't do anything
517         if ( iwidth != owidth || iheight != oheight )
518         {
519                 // Create the output image
520                 // IRRIGATE ME
521                 uint8_t *output = malloc( owidth * ( oheight + 1 ) * 2 );
522
523                 // Call the generic resize
524                 mlt_resize_yuv422( output, owidth, oheight, input, iwidth, iheight );
525
526                 // Now update the frame
527                 mlt_properties_set_data( properties, "image", output, owidth * ( oheight + 1 ) * 2, free, NULL );
528                 mlt_properties_set_int( properties, "width", owidth );
529                 mlt_properties_set_int( properties, "height", oheight );
530
531                 // Return the output
532                 return output;
533         }
534         // No change, return input
535         return input;
536 }
537
538 /** A rescaling function for yuv422 frames - low quality, and provided for testing
539         only. It assumes yuv422 images available on the frame so use with care.
540 */
541
542 uint8_t *mlt_frame_rescale_yuv422( mlt_frame this, int owidth, int oheight )
543 {
544         // Get properties
545         mlt_properties properties = mlt_frame_properties( this );
546
547         // Get the input image, width and height
548         uint8_t *input = mlt_properties_get_data( properties, "image", NULL );
549         int iwidth = mlt_properties_get_int( properties, "width" );
550         int iheight = mlt_properties_get_int( properties, "height" );
551
552         // If width and height are correct, don't do anything
553         if ( iwidth != owidth || iheight != oheight )
554         {
555                 // Create the output image
556                 // IRRIGATE ME
557                 uint8_t *output = malloc( owidth * ( oheight + 1 ) * 2 );
558
559                 // Calculate strides
560                 int istride = iwidth * 2;
561                 int ostride = owidth * 2;
562
563                 iwidth = iwidth - ( iwidth % 4 );
564
565         // Coordinates (0,0 is middle of output)
566         int y, x;
567
568                 // Derived coordinates
569                 int dy, dx;
570
571         // Calculate ranges
572         int out_x_range = owidth / 2;
573         int out_y_range = oheight / 2;
574         int in_x_range = iwidth / 2;
575         int in_y_range = iheight / 2;
576
577         // Output pointers
578         uint8_t *out_line = output;
579         uint8_t *out_ptr;
580
581         // Calculate a middle pointer
582         uint8_t *in_middle = input + istride * in_y_range + in_x_range * 2;
583         uint8_t *in_line;
584                 uint8_t *in_ptr;
585
586                 // Generate the affine transform scaling values
587                 int scale_width = ( iwidth << 16 ) / owidth;
588                 int scale_height = ( iheight << 16 ) / oheight;
589
590         // Loop for the entirety of our output height.
591         for ( y = - out_y_range; y < out_y_range ; y ++ )
592         {
593                         // Calculate the derived y value
594                         dy = ( scale_height * y ) >> 16;
595
596                 // Start at the beginning of the line
597                 out_ptr = out_line;
598         
599                 // Pointer to the middle of the input line
600                 in_line = in_middle + dy * istride;
601         
602                 // Loop for the entirety of our output row.
603                 for ( x = - out_x_range; x < out_x_range; x += 1 )
604                 {
605                                 // Calculated the derived x
606                                 dx = ( scale_width * x ) >> 16;
607
608                 // We're in the input range for this row.
609                                 in_ptr = in_line + ( dx << 1 );
610                 *out_ptr ++ = *in_ptr ++;
611                                 in_ptr = in_line + ( ( dx >> 1 ) << 2 ) + ( ( x & 1 ) << 1 ) + 1;
612                 *out_ptr ++ = *in_ptr;
613                 }
614
615                 // Move to next output line
616                 out_line += ostride;
617         }
618
619                 // Now update the frame
620                 mlt_properties_set_data( properties, "image", output, owidth * oheight * 2, free, NULL );
621                 mlt_properties_set_int( properties, "width", owidth );
622                 mlt_properties_set_int( properties, "height", oheight );
623
624                 // Return the output
625                 return output;
626         }
627
628         // No change, return input
629         return input;
630 }
631
632 int mlt_frame_mix_audio( mlt_frame this, mlt_frame that, float weight_start, float weight_end, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
633 {
634         int ret = 0;
635         int16_t *p_src, *p_dest;
636         int16_t *src, *dest;
637         //static int16_t *extra_src = NULL, *extra_dest = NULL;
638         static int extra_src_samples = 0, extra_dest_samples = 0;
639         int frequency_src = *frequency, frequency_dest = *frequency;
640         int channels_src = *channels, channels_dest = *channels;
641         int samples_src = *samples, samples_dest = *samples;
642         int i, j;
643         double d = 0, s = 0;
644
645         mlt_frame_get_audio( this, &p_dest, format, &frequency_dest, &channels_dest, &samples_dest );
646         //fprintf( stderr, "mix: frame dest samples %d channels %d position %lld\n", samples_dest, channels_dest, mlt_properties_get_position( mlt_frame_properties( this ), "_position" ) );
647         mlt_frame_get_audio( that, &p_src, format, &frequency_src, &channels_src, &samples_src );
648         //fprintf( stderr, "mix: frame src  samples %d channels %d\n", samples_src, channels_src );
649         src = p_src;
650         dest = p_dest;
651         if ( channels_src > 6 )
652                 channels_src = 0;
653         if ( channels_dest > 6 )
654                 channels_dest = 0;
655         if ( samples_src > 4000 )
656                 samples_src = 0;
657         if ( samples_dest > 4000 )
658                 samples_dest = 0;
659
660 #if 0
661         // Append new samples to leftovers
662         if ( extra_dest_samples > 0 )
663         {
664                 fprintf( stderr, "prepending %d samples to dest\n", extra_dest_samples );
665                 dest = realloc( extra_dest, ( samples_dest + extra_dest_samples ) * 2 * channels_dest );
666                 memcpy( &extra_dest[ extra_dest_samples * channels_dest ], p_dest, samples_dest * 2 * channels_dest );
667         }
668         else
669                 dest = p_dest;
670         if ( extra_src_samples > 0 )
671         {
672                 fprintf( stderr, "prepending %d samples to src\n", extra_src_samples );
673                 src = realloc( extra_src, ( samples_src + extra_src_samples ) * 2 * channels_src );
674                 memcpy( &extra_src[ extra_src_samples * channels_src ], p_src, samples_src * 2 * channels_src );
675         }
676         else
677                 src = p_src;
678 #endif
679
680         // determine number of samples to process       
681         if ( samples_src + extra_src_samples < samples_dest + extra_dest_samples )
682                 *samples = samples_src + extra_src_samples;
683         else if ( samples_dest + extra_dest_samples < samples_src + extra_src_samples )
684                 *samples = samples_dest + extra_dest_samples;
685         
686         *channels = channels_src < channels_dest ? channels_src : channels_dest;
687         *buffer = p_dest;
688         *frequency = frequency_dest;
689
690         // Compute a smooth ramp over start to end
691         float weight = weight_start;
692         float weight_step = ( weight_end - weight_start ) / *samples;
693
694         // Mixdown
695         for ( i = 0; i < *samples; i++ )
696         {
697                 for ( j = 0; j < *channels; j++ )
698                 {
699                         if ( j < channels_dest )
700                                 d = (double) dest[ i * channels_dest + j ];
701                         if ( j < channels_src )
702                                 s = (double) src[ i * channels_src + j ];
703                         dest[ i * channels_dest + j ] = s * weight + d * ( 1.0 - weight );
704                 }
705                 weight += weight_step;
706         }
707
708         // We have to copy --sigh
709         if ( dest != p_dest )
710                 memcpy( p_dest, dest, *samples * 2 * *channels );
711
712 #if 0
713         // Store the leftovers
714         if ( samples_src + extra_src_samples < samples_dest + extra_dest_samples )
715         {
716                 extra_dest_samples = ( samples_dest + extra_dest_samples ) - ( samples_src + extra_src_samples );
717                 size_t size = extra_dest_samples * 2 * channels_dest;
718                 fprintf( stderr, "storing %d samples from dest\n", extra_dest_samples );
719                 if ( extra_dest )
720                         free( extra_dest );
721                 extra_dest = malloc( size );
722                 if ( extra_dest )
723                         memcpy( extra_dest, &p_dest[ ( samples_dest - extra_dest_samples - 1 ) * channels_dest ], size );
724                 else
725                         extra_dest_samples = 0;
726         }
727         else if ( samples_dest + extra_dest_samples < samples_src + extra_src_samples )
728         {
729                 extra_src_samples = ( samples_src + extra_src_samples ) - ( samples_dest + extra_dest_samples );
730                 size_t size = extra_src_samples * 2 * channels_src;
731                 fprintf( stderr, "storing %d samples from src\n", extra_dest_samples );
732                 if ( extra_src )
733                         free( extra_src );
734                 extra_src = malloc( size );
735                 if ( extra_src )
736                         memcpy( extra_src, &p_src[ ( samples_src - extra_src_samples - 1 ) * channels_src ], size );
737                 else
738                         extra_src_samples = 0;
739         }
740 #endif
741         
742         return ret;
743 }
744
745 int mlt_sample_calculator( float fps, int frequency, int64_t position )
746 {
747         int samples = 0;
748
749         if ( fps > 29 && fps <= 30 )
750         {
751                 samples = frequency / 30;
752
753                 switch ( frequency )
754                 {
755                         case 48000:
756                                 if ( position % 5 != 0 )
757                                         samples += 2;
758                                 break;
759                         case 44100:
760                                 if ( position % 300 == 0 )
761                                         samples = 1471;
762                                 else if ( position % 30 == 0 )
763                                         samples = 1470;
764                                 else if ( position % 2 == 0 )
765                                         samples = 1472;
766                                 else
767                                         samples = 1471;
768                                 break;
769                         case 32000:
770                                 if ( position % 30 == 0 )
771                                         samples = 1068;
772                                 else if ( position % 29 == 0 )
773                                         samples = 1067;
774                                 else if ( position % 4 == 2 )
775                                         samples = 1067;
776                                 else
777                                         samples = 1068;
778                                 break;
779                         default:
780                                 samples = 0;
781                 }
782         }
783         else if ( fps != 0 )
784         {
785                 samples = frequency / fps;
786         }
787
788         return samples;
789 }
790