]> git.sesse.net Git - mlt/blob - src/framework/mlt_frame.c
Luma and composite fixes
[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 "mlt_factory.h"
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 /** Constructor for a frame.
30 */
31
32 mlt_frame mlt_frame_init( )
33 {
34         // Allocate a frame
35         mlt_frame this = calloc( sizeof( struct mlt_frame_s ), 1 );
36
37         if ( this != NULL )
38         {
39                 // Get the normalisation
40                 char *normalisation = mlt_environment( "MLT_NORMALISATION" );
41
42                 // Initialise the properties
43                 mlt_properties properties = &this->parent;
44                 mlt_properties_init( properties, this );
45
46                 // Set default properties on the frame
47                 mlt_properties_set_position( properties, "_position", 0.0 );
48                 mlt_properties_set_data( properties, "image", NULL, 0, NULL, NULL );
49
50                 if ( normalisation == NULL || strcmp( normalisation, "NTSC" ) )
51                 {
52                         mlt_properties_set_int( properties, "width", 720 );
53                         mlt_properties_set_int( properties, "height", 576 );
54                         mlt_properties_set_int( properties, "normalised_width", 720 );
55                         mlt_properties_set_int( properties, "normalised_height", 576 );
56                         mlt_properties_set_double( properties, "aspect_ratio", 59.0/54.0 );
57                 }
58                 else
59                 {
60                         mlt_properties_set_int( properties, "width", 720 );
61                         mlt_properties_set_int( properties, "height", 480 );
62                         mlt_properties_set_int( properties, "normalised_width", 720 );
63                         mlt_properties_set_int( properties, "normalised_height", 480 );
64                         mlt_properties_set_double( properties, "aspect_ratio", 10.0/11.0 );
65                 }
66
67                 mlt_properties_set_data( properties, "audio", NULL, 0, NULL, NULL );
68                 mlt_properties_set_data( properties, "alpha", NULL, 0, NULL, NULL );
69
70                 // Construct stacks for frames and methods
71                 this->stack_image = mlt_deque_init( );
72                 this->stack_audio = mlt_deque_init( );
73                 this->stack_service = mlt_deque_init( );
74         }
75
76         return this;
77 }
78
79 /** Fetch the frames properties.
80 */
81
82 mlt_properties mlt_frame_properties( mlt_frame this )
83 {
84         return this != NULL ? &this->parent : NULL;
85 }
86
87 /** Check if we have a way to derive something other than a test card.
88 */
89
90 int mlt_frame_is_test_card( mlt_frame this )
91 {
92         return mlt_deque_count( this->stack_image ) == 0 || mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "test_image" );
93 }
94
95 /** Check if we have a way to derive something than test audio.
96 */
97
98 int mlt_frame_is_test_audio( mlt_frame this )
99 {
100         return this->get_audio == NULL || mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "test_audio" );
101 }
102
103 /** Get the aspect ratio of the frame.
104 */
105
106 double mlt_frame_get_aspect_ratio( mlt_frame this )
107 {
108         return mlt_properties_get_double( MLT_FRAME_PROPERTIES( this ), "aspect_ratio" );
109 }
110
111 /** Set the aspect ratio of the frame.
112 */
113
114 int mlt_frame_set_aspect_ratio( mlt_frame this, double value )
115 {
116         return mlt_properties_set_double( MLT_FRAME_PROPERTIES( this ), "aspect_ratio", value );
117 }
118
119 /** Get the position of this frame.
120 */
121
122 mlt_position mlt_frame_get_position( mlt_frame this )
123 {
124         int pos = mlt_properties_get_position( MLT_FRAME_PROPERTIES( this ), "_position" );
125         return pos < 0 ? 0 : pos;
126 }
127
128 /** Set the position of this frame.
129 */
130
131 int mlt_frame_set_position( mlt_frame this, mlt_position value )
132 {
133         return mlt_properties_set_position( MLT_FRAME_PROPERTIES( this ), "_position", value );
134 }
135
136 /** Stack a get_image callback.
137 */
138
139 int mlt_frame_push_get_image( mlt_frame this, mlt_get_image get_image )
140 {
141         return mlt_deque_push_back( this->stack_image, get_image );
142 }
143
144 /** Pop a get_image callback.
145 */
146
147 mlt_get_image mlt_frame_pop_get_image( mlt_frame this )
148 {
149         return mlt_deque_pop_back( this->stack_image );
150 }
151
152 /** Push a frame.
153 */
154
155 int mlt_frame_push_frame( mlt_frame this, mlt_frame that )
156 {
157         return mlt_deque_push_back( this->stack_image, that );
158 }
159
160 /** Pop a frame.
161 */
162
163 mlt_frame mlt_frame_pop_frame( mlt_frame this )
164 {
165         return mlt_deque_pop_back( this->stack_image );
166 }
167
168 /** Push a service.
169 */
170
171 int mlt_frame_push_service( mlt_frame this, void *that )
172 {
173         return mlt_deque_push_back( this->stack_image, that );
174 }
175
176 /** Pop a service.
177 */
178
179 void *mlt_frame_pop_service( mlt_frame this )
180 {
181         return mlt_deque_pop_back( this->stack_image );
182 }
183
184 /** Push an audio item on the stack.
185 */
186
187 int mlt_frame_push_audio( mlt_frame this, void *that )
188 {
189         return mlt_deque_push_back( this->stack_audio, that );
190 }
191
192 /** Pop an audio item from the stack
193 */
194
195 void *mlt_frame_pop_audio( mlt_frame this )
196 {
197         return mlt_deque_pop_back( this->stack_audio );
198 }
199
200 /** Return the service stack
201 */
202
203 mlt_deque mlt_frame_service_stack( mlt_frame this )
204 {
205         return this->stack_service;
206 }
207
208 int mlt_frame_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
209 {
210         mlt_properties properties = MLT_FRAME_PROPERTIES( this );
211         mlt_get_image get_image = mlt_frame_pop_get_image( this );
212         mlt_producer producer = mlt_properties_get_data( properties, "test_card_producer", NULL );
213
214         *width = *width >> 1 << 1;
215         
216         if ( get_image != NULL )
217         {
218                 int error = 0;
219                 mlt_position position = mlt_frame_get_position( this );
220                 error = get_image( this, buffer, format, width, height, writable );
221                 mlt_frame_set_position( this, position );
222                 return error;
223         }
224         else if ( mlt_properties_get_data( properties, "image", NULL ) != NULL )
225         {
226                 *format = mlt_image_yuv422;
227                 *buffer = mlt_properties_get_data( properties, "image", NULL );
228                 *width = mlt_properties_get_int( properties, "width" );
229                 *height = mlt_properties_get_int( properties, "height" );
230         }
231         else if ( producer != NULL )
232         {
233                 mlt_frame test_frame = NULL;
234                 mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &test_frame, 0 );
235                 if ( test_frame != NULL )
236                 {
237                         mlt_properties test_properties = MLT_FRAME_PROPERTIES( test_frame );
238                         mlt_properties_set_double( test_properties, "consumer_aspect_ratio", mlt_properties_get_double( properties, "consumer_aspect_ratio" ) );
239                         mlt_properties_set( test_properties, "rescale.interp", mlt_properties_get( properties, "rescale.interp" ) );
240                         mlt_frame_get_image( test_frame, buffer, format, width, height, writable );
241                         mlt_properties_set_data( properties, "test_card_frame", test_frame, 0, ( mlt_destructor )mlt_frame_close, NULL );
242                         mlt_properties_set_data( properties, "image", *buffer, *width * *height * 2, NULL, NULL );
243                         mlt_properties_set_int( properties, "width", *width );
244                         mlt_properties_set_int( properties, "height", *height );
245                         mlt_properties_set_double( properties, "aspect_ratio", mlt_frame_get_aspect_ratio( test_frame ) );
246                 }
247                 else
248                 {
249                         mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL );
250                         mlt_frame_get_image( this, buffer, format, width, height, writable );
251                 }
252         }
253         else
254         {
255                 register uint8_t *p;
256                 register uint8_t *q;
257                 int size = 0;
258
259                 *width = *width == 0 ? 720 : *width;
260                 *height = *height == 0 ? 576 : *height;
261                 size = *width * *height;
262
263                 mlt_properties_set_int( properties, "width", *width );
264                 mlt_properties_set_int( properties, "height", *height );
265                 mlt_properties_set_int( properties, "aspect_ratio", 1 );
266
267                 switch( *format )
268                 {
269                         case mlt_image_none:
270                                 size = 0;
271                                 *buffer = NULL;
272                                 break;
273                         case mlt_image_rgb24:
274                                 size *= 3;
275                                 size += *width * 3;
276                                 *buffer = mlt_pool_alloc( size );
277                                 if ( *buffer )
278                                         memset( *buffer, 255, size );
279                                 break;
280                         case mlt_image_rgb24a:
281                                 size *= 4;
282                                 size += *width * 4;
283                                 *buffer = mlt_pool_alloc( size );
284                                 if ( *buffer )
285                                         memset( *buffer, 255, size );
286                                 break;
287                         case mlt_image_yuv422:
288                                 size *= 2;
289                                 size += *width * 2;
290                                 *buffer = mlt_pool_alloc( size );
291                                 p = *buffer;
292                                 q = p + size;
293                                 while ( p != NULL && p != q )
294                                 {
295                                         *p ++ = 235;
296                                         *p ++ = 128;
297                                 }
298                                 break;
299                         case mlt_image_yuv420p:
300                                 size = size * 3 / 2;
301                                 *buffer = mlt_pool_alloc( size );
302                                 if ( *buffer )
303                                         memset( *buffer, 255, size );
304                                 break;
305                 }
306
307                 mlt_properties_set_data( properties, "image", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL );
308                 mlt_properties_set_int( properties, "test_image", 1 );
309         }
310
311         return 0;
312 }
313
314 uint8_t *mlt_frame_get_alpha_mask( mlt_frame this )
315 {
316         if ( this != NULL && this->get_alpha_mask != NULL )
317                 return this->get_alpha_mask( this );
318         return this == NULL ? NULL : mlt_properties_get_data( &this->parent, "alpha", NULL );
319 }
320
321 int mlt_frame_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
322 {
323         mlt_properties properties = MLT_FRAME_PROPERTIES( this );
324         int hide = mlt_properties_get_int( properties, "test_audio" );
325
326         if ( hide == 0 && this->get_audio != NULL )
327         {
328                 mlt_position position = mlt_frame_get_position( this );
329                 this->get_audio( this, buffer, format, frequency, channels, samples );
330                 mlt_frame_set_position( this, position );
331         }
332         else if ( mlt_properties_get_data( properties, "audio", NULL ) )
333         {
334                 *buffer = mlt_properties_get_data( properties, "audio", NULL );
335                 *frequency = mlt_properties_get_int( properties, "audio_frequency" );
336                 *channels = mlt_properties_get_int( properties, "audio_channels" );
337                 *samples = mlt_properties_get_int( properties, "audio_samples" );
338         }
339         else
340         {
341                 int size = 0;
342                 *samples = *samples <= 0 ? 1920 : *samples;
343                 *channels = *channels <= 0 ? 2 : *channels;
344                 *frequency = *frequency <= 0 ? 48000 : *frequency;
345                 size = *samples * *channels * sizeof( int16_t );
346                 *buffer = mlt_pool_alloc( size );
347                 if ( *buffer != NULL )
348                         memset( *buffer, 0, size );
349                 mlt_properties_set_data( properties, "audio", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL );
350                 mlt_properties_set_int( properties, "test_audio", 1 );
351         }
352
353         mlt_properties_set_int( properties, "audio_frequency", *frequency );
354         mlt_properties_set_int( properties, "audio_channels", *channels );
355         mlt_properties_set_int( properties, "audio_samples", *samples );
356
357         if ( mlt_properties_get( properties, "meta.volume" ) )
358         {
359                 double value = mlt_properties_get_double( properties, "meta.volume" );
360                 if ( value == 0.0 )
361                 {
362                         memset( *buffer, 0, *samples * *channels * 2 );
363                         mlt_properties_set_double( properties, "meta.volume", 1.0 );
364                 }
365                 else if ( value != 1.0 )
366                 {
367                         int total = *samples * *channels;
368                         int16_t *p = *buffer;
369                         while ( total -- )
370                         {
371                                 *p = *p * value;
372                                 p ++;
373                         }
374                         mlt_properties_set_double( properties, "meta.volume", 1.0 );
375                 }
376         }
377
378         return 0;
379 }
380
381 unsigned char *mlt_frame_get_waveform( mlt_frame this, int w, int h )
382 {
383         int16_t *pcm = NULL;
384         mlt_properties properties = MLT_FRAME_PROPERTIES( this );
385         mlt_audio_format format = mlt_audio_pcm;
386         int frequency = 32000; // lower frequency available?
387         int channels = 2;
388         double fps = mlt_properties_get_double( properties, "fps" );
389         int samples = mlt_sample_calculator( fps, frequency, mlt_frame_get_position( this ) );
390         
391         // Get the pcm data
392         mlt_frame_get_audio( this, &pcm, &format, &frequency, &channels, &samples );
393         
394         // Make an 8-bit buffer large enough to hold rendering
395         int size = w * h;
396         unsigned char *bitmap = ( unsigned char* )mlt_pool_alloc( size );
397         if ( bitmap != NULL )
398                 memset( bitmap, 0, size );
399         mlt_properties_set_data( properties, "waveform", bitmap, size, ( mlt_destructor )mlt_pool_release, NULL );
400         
401         // Render vertical lines
402         int16_t *ubound = pcm + samples * channels;
403         int skip = samples / w - 1;
404         int i, j, k;
405         
406         // Iterate sample stream and along x coordinate
407         for ( i = 0; i < w && pcm < ubound; i++ )
408         {
409                 // pcm data has channels interleaved
410                 for ( j = 0; j < channels; j++ )
411                 {
412                         // Determine sample's magnitude from 2s complement;
413                         int pcm_magnitude = *pcm < 0 ? ~(*pcm) + 1 : *pcm;
414                         // The height of a line is the ratio of the magnitude multiplied by 
415                         // half the vertical resolution
416                         int height = ( int )( ( double )( pcm_magnitude ) / 32768 * h / 2 );
417                         // Determine the starting y coordinate - left channel above center,
418                         // right channel below - currently assumes 2 channels
419                         int displacement = ( h / 2 ) - ( 1 - j ) * height;
420                         // Position buffer pointer using y coordinate, stride, and x coordinate
421                         unsigned char *p = &bitmap[ i + displacement * w ];
422                         
423                         // Draw vertical line
424                         for ( k = 0; k < height; k++ )
425                                 p[ w * k ] = 0xFF;
426                         
427                         pcm++;
428                 }
429                 pcm += skip * channels;
430         }
431
432         return bitmap;
433 }
434
435 mlt_producer mlt_frame_get_original_producer( mlt_frame this )
436 {
437         if ( this != NULL )
438                 return mlt_properties_get_data( MLT_FRAME_PROPERTIES( this ), "_producer", NULL );
439         return NULL;
440 }
441
442 void mlt_frame_close( mlt_frame this )
443 {
444         if ( this != NULL && mlt_properties_dec_ref( MLT_FRAME_PROPERTIES( this ) ) <= 0 )
445         {
446                 mlt_deque_close( this->stack_image );
447                 mlt_deque_close( this->stack_audio );
448                 while( mlt_deque_peek_back( this->stack_service ) )
449                         mlt_service_close( mlt_deque_pop_back( this->stack_service ) );
450                 mlt_deque_close( this->stack_service );
451                 mlt_properties_close( &this->parent );
452                 free( this );
453         }
454 }
455
456 /***** convenience functions *****/
457
458 int mlt_convert_rgb24a_to_yuv422( uint8_t *rgba, int width, int height, int stride, uint8_t *yuv, uint8_t *alpha )
459 {
460         int ret = 0;
461         register int y0, y1, u0, u1, v0, v1;
462         register int r, g, b;
463         register uint8_t *d = yuv;
464         register int i, j;
465
466         for ( i = 0; i < height; i++ )
467         {
468                 register uint8_t *s = rgba + ( stride * i );
469                 for ( j = 0; j < ( width / 2 ); j++ )
470                 {
471                         r = *s++;
472                         g = *s++;
473                         b = *s++;
474                         *alpha++ = *s++;
475                         RGB2YUV (r, g, b, y0, u0 , v0);
476                         r = *s++;
477                         g = *s++;
478                         b = *s++;
479                         *alpha++ = *s++;
480                         RGB2YUV (r, g, b, y1, u1 , v1);
481                         *d++ = y0;
482                         *d++ = (u0+u1) >> 1;
483                         *d++ = y1;
484                         *d++ = (v0+v1) >> 1;
485                 }
486                 if ( width % 2 )
487                 {
488                         r = *s++;
489                         g = *s++;
490                         b = *s++;
491                         *alpha++ = *s++;
492                         RGB2YUV (r, g, b, y0, u0 , v0);
493                         *d++ = y0;
494                         *d++ = u0;
495                 }
496         }
497         return ret;
498 }
499
500 int mlt_convert_rgb24_to_yuv422( uint8_t *rgb, int width, int height, int stride, uint8_t *yuv )
501 {
502         int ret = 0;
503         register int y0, y1, u0, u1, v0, v1;
504         register int r, g, b;
505         register uint8_t *d = yuv;
506         register int i, j;
507
508         for ( i = 0; i < height; i++ )
509         {
510                 register uint8_t *s = rgb + ( stride * i );
511                 for ( j = 0; j < ( width / 2 ); j++ )
512                 {
513                         r = *s++;
514                         g = *s++;
515                         b = *s++;
516                         RGB2YUV (r, g, b, y0, u0 , v0);
517                         r = *s++;
518                         g = *s++;
519                         b = *s++;
520                         RGB2YUV (r, g, b, y1, u1 , v1);
521                         *d++ = y0;
522                         *d++ = (u0+u1) >> 1;
523                         *d++ = y1;
524                         *d++ = (v0+v1) >> 1;
525                 }
526                 if ( width % 2 )
527                 {
528                         r = *s++;
529                         g = *s++;
530                         b = *s++;
531                         RGB2YUV (r, g, b, y0, u0 , v0);
532                         *d++ = y0;
533                         *d++ = u0;
534                 }
535         }
536         return ret;
537 }
538
539 int mlt_convert_yuv420p_to_yuv422( uint8_t *yuv420p, int width, int height, int stride, uint8_t *yuv )
540 {
541         int ret = 0;
542         register int i, j;
543
544         int half = width >> 1;
545
546         uint8_t *Y = yuv420p;
547         uint8_t *U = Y + width * height;
548         uint8_t *V = U + width * height / 4;
549
550         register uint8_t *d = yuv;
551
552         for ( i = 0; i < height; i++ )
553         {
554                 register uint8_t *u = U + ( i / 2 ) * ( half );
555                 register uint8_t *v = V + ( i / 2 ) * ( half );
556
557                 for ( j = 0; j < half; j++ )
558                 {
559                         *d ++ = *Y ++;
560                         *d ++ = *u ++;
561                         *d ++ = *Y ++;
562                         *d ++ = *v ++;
563                 }
564         }
565         return ret;
566 }
567
568 uint8_t *mlt_resize_alpha( uint8_t *input, int owidth, int oheight, int iwidth, int iheight )
569 {
570         uint8_t *output = NULL;
571
572         if ( input != NULL && ( iwidth != owidth || iheight != oheight ) && ( owidth > 6 && oheight > 6 ) )
573         {
574                 iwidth = iwidth - ( iwidth % 2 );
575                 owidth = owidth - ( owidth % 2 );
576
577                 output = mlt_pool_alloc( owidth * oheight );
578
579                 // Coordinates (0,0 is middle of output)
580                 int y;
581
582                 // Calculate ranges
583                 int out_x_range = owidth / 2;
584                 int out_y_range = oheight / 2;
585                 int in_x_range = iwidth / 2 < out_x_range ? iwidth / 2 : out_x_range;
586                 int in_y_range = iheight / 2 < out_y_range ? iheight / 2 : out_y_range;
587
588                 // Output pointers
589                 uint8_t *out_line = output;
590                 uint8_t *out_ptr = out_line;
591
592                 // Calculate a middle and possibly invalid pointer in the input
593                 uint8_t *in_middle = input + iwidth * ( iheight / 2 ) + ( iwidth / 2 );
594                 int in_line = - in_y_range * iwidth - in_x_range;
595
596                 int elements;
597
598                 // Fill whole section with black
599                 y = out_y_range - ( iheight / 2 );
600                 int blank_elements = owidth * y;
601                 elements = blank_elements;
602                 while ( elements -- )
603                         *out_line ++ = 0;
604
605                 int active_width = iwidth;
606                 int inactive_width = out_x_range - in_x_range;
607                 uint8_t *p = NULL;
608                 uint8_t *end = NULL;
609
610                 // Loop for the entirety of our output height.
611                 while ( iheight -- )
612                 {
613                 // Start at the beginning of the line
614                 out_ptr = out_line;
615
616                         // Fill the outer part with black
617                         elements = inactive_width;
618                         while ( elements -- )
619                                 *out_ptr ++ = 0;
620
621                         // We're in the input range for this row.
622                         p = in_middle + in_line;
623                         end = out_ptr + active_width;
624                         while ( out_ptr != end )
625                                 *out_ptr ++ = *p ++;
626
627                         // Fill the outer part with black
628                         elements = inactive_width;
629                         while ( elements -- )
630                                 *out_ptr ++ = 0;
631         
632                         // Move to next input line
633                         in_line += iwidth;
634
635                 // Move to next output line
636                 out_line += owidth;
637                 }
638
639                 // Fill whole section with black
640                 elements = blank_elements;
641                 while ( elements -- )
642                         *out_line ++ = 0;
643         }
644
645         return output;
646 }
647
648 void mlt_resize_yuv422( uint8_t *output, int owidth, int oheight, uint8_t *input, int iwidth, int iheight )
649 {
650         // Calculate strides
651         int istride = iwidth * 2;
652         int ostride = owidth * 2;
653
654         iwidth = iwidth - ( iwidth % 2 );
655         owidth = owidth - ( owidth % 2 );
656         //iheight = iheight - ( iheight % 2 );
657         //oheight = oheight - ( oheight % 2 );
658         
659         // Optimisation point
660         if ( output == NULL || input == NULL || ( owidth <= 6 || oheight <= 6 || iwidth <= 6 || oheight <= 6 ) )
661         {
662                 return;
663         }
664         else if ( iwidth == owidth && iheight == oheight )
665         {
666                 memcpy( output, input, iheight * istride );
667                 return;
668         }
669
670         // Coordinates (0,0 is middle of output)
671         int y;
672
673         // Calculate ranges
674         int out_x_range = owidth / 2;
675         int out_y_range = oheight / 2;
676         int in_x_range = iwidth / 2 < out_x_range ? iwidth / 2 : out_x_range;
677         int in_y_range = iheight / 2 < out_y_range ? iheight / 2 : out_y_range;
678
679         // Output pointers
680         uint8_t *out_line = output;
681         uint8_t *out_ptr = out_line;
682
683         // Calculate a middle and possibly invalid pointer in the input
684         uint8_t *in_middle = input + istride * ( iheight / 2 ) + ( iwidth / 2 ) * 2;
685         int in_line = - in_y_range * istride - in_x_range * 2;
686
687         int elements;
688
689         // Fill whole section with black
690         y = out_y_range - ( iheight / 2 );
691         int blank_elements = ostride * y / 2;
692         elements = blank_elements;
693         while ( elements -- )
694         {
695                 *out_line ++ = 16;
696                 *out_line ++ = 128;
697         }
698
699         int active_width = 2 * iwidth;
700         int inactive_width = out_x_range - in_x_range;
701         uint8_t *p = NULL;
702         uint8_t *end = NULL;
703
704         // Loop for the entirety of our output height.
705         while ( iheight -- )
706         {
707         // Start at the beginning of the line
708         out_ptr = out_line;
709
710                 // Fill the outer part with black
711                 elements = inactive_width;
712                 while ( elements -- )
713                 {
714                         *out_ptr ++ = 16;
715                         *out_ptr ++ = 128;
716                 }
717
718                 // We're in the input range for this row.
719                 p = in_middle + in_line;
720                 end = out_ptr + active_width;
721                 while ( out_ptr != end )
722                 {
723                         *out_ptr ++ = *p ++;
724                         *out_ptr ++ = *p ++;
725                 }
726
727                 // Fill the outer part with black
728                 elements = inactive_width;
729                 while ( elements -- )
730                 {
731                         *out_ptr ++ = 16;
732                         *out_ptr ++ = 128;
733                 }
734
735                 // Move to next input line
736                 in_line += istride;
737
738         // Move to next output line
739         out_line += ostride;
740         }
741
742         // Fill whole section with black
743         elements = blank_elements;
744         while ( elements -- )
745         {
746                 *out_line ++ = 16;
747                 *out_line ++ = 128;
748         }
749 }
750
751 /** A resizing function for yuv422 frames - this does not rescale, but simply
752         resizes. It assumes yuv422 images available on the frame so use with care.
753 */
754
755 uint8_t *mlt_frame_resize_yuv422( mlt_frame this, int owidth, int oheight )
756 {
757         // Get properties
758         mlt_properties properties = MLT_FRAME_PROPERTIES( this );
759
760         // Get the input image, width and height
761         uint8_t *input = mlt_properties_get_data( properties, "image", NULL );
762         uint8_t *alpha = mlt_frame_get_alpha_mask( this );
763
764         int iwidth = mlt_properties_get_int( properties, "width" );
765         int iheight = mlt_properties_get_int( properties, "height" );
766
767         // If width and height are correct, don't do anything
768         if ( iwidth != owidth || iheight != oheight )
769         {
770                 // Create the output image
771                 uint8_t *output = mlt_pool_alloc( owidth * ( oheight + 1 ) * 2 );
772
773                 // Call the generic resize
774                 mlt_resize_yuv422( output, owidth, oheight, input, iwidth, iheight );
775
776                 // Now update the frame
777                 mlt_properties_set_data( properties, "image", output, owidth * ( oheight + 1 ) * 2, ( mlt_destructor )mlt_pool_release, NULL );
778                 mlt_properties_set_int( properties, "width", owidth );
779                 mlt_properties_set_int( properties, "height", oheight );
780
781                 // We should resize the alpha too
782                 alpha = mlt_resize_alpha( alpha, owidth, oheight, iwidth, iheight );
783                 if ( alpha != NULL )
784                 {
785                         mlt_properties_set_data( properties, "alpha", alpha, owidth * ( oheight + 1 ), ( mlt_destructor )mlt_pool_release, NULL );
786                         this->get_alpha_mask = NULL;
787                 }
788
789                 // Return the output
790                 return output;
791         }
792         // No change, return input
793         return input;
794 }
795
796 /** A rescaling function for yuv422 frames - low quality, and provided for testing
797         only. It assumes yuv422 images available on the frame so use with care.
798 */
799
800 uint8_t *mlt_frame_rescale_yuv422( mlt_frame this, int owidth, int oheight )
801 {
802         // Get properties
803         mlt_properties properties = MLT_FRAME_PROPERTIES( this );
804
805         // Get the input image, width and height
806         uint8_t *input = mlt_properties_get_data( properties, "image", NULL );
807         int iwidth = mlt_properties_get_int( properties, "width" );
808         int iheight = mlt_properties_get_int( properties, "height" );
809
810         // If width and height are correct, don't do anything
811         if ( iwidth != owidth || iheight != oheight )
812         {
813                 // Create the output image
814                 uint8_t *output = mlt_pool_alloc( owidth * ( oheight + 1 ) * 2 );
815
816                 // Calculate strides
817                 int istride = iwidth * 2;
818                 int ostride = owidth * 2;
819
820                 iwidth = iwidth - ( iwidth % 4 );
821
822                 // Derived coordinates
823                 int dy, dx;
824
825         // Calculate ranges
826         int out_x_range = owidth / 2;
827         int out_y_range = oheight / 2;
828         int in_x_range = iwidth / 2;
829         int in_y_range = iheight / 2;
830
831         // Output pointers
832         register uint8_t *out_line = output;
833         register uint8_t *out_ptr;
834
835         // Calculate a middle pointer
836         uint8_t *in_middle = input + istride * in_y_range + in_x_range * 2;
837         uint8_t *in_line;
838
839                 // Generate the affine transform scaling values
840                 register int scale_width = ( iwidth << 16 ) / owidth;
841                 register int scale_height = ( iheight << 16 ) / oheight;
842                 register int base = 0;
843
844                 int outer = out_x_range * scale_width;
845                 int bottom = out_y_range * scale_height;
846
847         // Loop for the entirety of our output height.
848         for ( dy = - bottom; dy < bottom; dy += scale_height )
849         {
850                 // Start at the beginning of the line
851                 out_ptr = out_line;
852         
853                 // Pointer to the middle of the input line
854                 in_line = in_middle + ( dy >> 16 ) * istride;
855
856                 // Loop for the entirety of our output row.
857                 for ( dx = - outer; dx < outer; dx += scale_width )
858                 {
859                                 base = dx >> 15;
860                                 base &= 0xfffffffe;
861                                 *out_ptr ++ = *( in_line + base );
862                                 base &= 0xfffffffc;
863                                 *out_ptr ++ = *( in_line + base + 1 );
864                                 dx += scale_width;
865                                 base = dx >> 15;
866                                 base &= 0xfffffffe;
867                                 *out_ptr ++ = *( in_line + base );
868                                 base &= 0xfffffffc;
869                                 *out_ptr ++ = *( in_line + base + 3 );
870                 }
871
872                 // Move to next output line
873                 out_line += ostride;
874         }
875
876                 // Now update the frame
877                 mlt_properties_set_data( properties, "image", output, owidth * ( oheight + 1 ) * 2, ( mlt_destructor )mlt_pool_release, NULL );
878                 mlt_properties_set_int( properties, "width", owidth );
879                 mlt_properties_set_int( properties, "height", oheight );
880
881                 // Return the output
882                 return output;
883         }
884
885         // No change, return input
886         return input;
887 }
888
889 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 )
890 {
891         int ret = 0;
892         int16_t *src, *dest;
893         int frequency_src = *frequency, frequency_dest = *frequency;
894         int channels_src = *channels, channels_dest = *channels;
895         int samples_src = *samples, samples_dest = *samples;
896         int i, j;
897         double d = 0, s = 0;
898
899         mlt_frame_get_audio( this, &dest, format, &frequency_dest, &channels_dest, &samples_dest );
900         mlt_frame_get_audio( that, &src, format, &frequency_src, &channels_src, &samples_src );
901
902         int silent = mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "silent_audio" );
903         mlt_properties_set_int( MLT_FRAME_PROPERTIES( this ), "silent_audio", 0 );
904         if ( silent )
905                 memset( dest, 0, samples_dest * channels_dest * sizeof( int16_t ) );
906
907         silent = mlt_properties_get_int( MLT_FRAME_PROPERTIES( that ), "silent_audio" );
908         mlt_properties_set_int( MLT_FRAME_PROPERTIES( that ), "silent_audio", 0 );
909         if ( silent )
910                 memset( src, 0, samples_src * channels_src * sizeof( int16_t ) );
911
912         if ( channels_src > 6 )
913                 channels_src = 0;
914         if ( channels_dest > 6 )
915                 channels_dest = 0;
916         if ( samples_src > 4000 )
917                 samples_src = 0;
918         if ( samples_dest > 4000 )
919                 samples_dest = 0;
920
921         // determine number of samples to process
922         *samples = samples_src < samples_dest ? samples_src : samples_dest;
923         *channels = channels_src < channels_dest ? channels_src : channels_dest;
924         *buffer = dest;
925         *frequency = frequency_dest;
926
927         // Compute a smooth ramp over start to end
928         float weight = weight_start;
929         float weight_step = ( weight_end - weight_start ) / *samples;
930
931         // Mixdown
932         for ( i = 0; i < *samples; i++ )
933         {
934                 for ( j = 0; j < *channels; j++ )
935                 {
936                         if ( j < channels_dest )
937                                 d = (double) dest[ i * channels_dest + j ];
938                         if ( j < channels_src )
939                                 s = (double) src[ i * channels_src + j ];
940                         dest[ i * channels_dest + j ] = s * weight + d * ( 1.0 - weight );
941                 }
942                 weight += weight_step;
943         }
944
945         return ret;
946 }
947
948 int mlt_sample_calculator( float fps, int frequency, int64_t position )
949 {
950         int samples = 0;
951
952         if ( ( int )( fps * 100 ) == 2997 )
953         {
954                 samples = frequency / 30;
955
956                 switch ( frequency )
957                 {
958                         case 48000:
959                                 if ( position % 5 != 0 )
960                                         samples += 2;
961                                 break;
962                         case 44100:
963                                 if ( position % 300 == 0 )
964                                         samples = 1471;
965                                 else if ( position % 30 == 0 )
966                                         samples = 1470;
967                                 else if ( position % 2 == 0 )
968                                         samples = 1472;
969                                 else
970                                         samples = 1471;
971                                 break;
972                         case 32000:
973                                 if ( position % 30 == 0 )
974                                         samples = 1068;
975                                 else if ( position % 29 == 0 )
976                                         samples = 1067;
977                                 else if ( position % 4 == 2 )
978                                         samples = 1067;
979                                 else
980                                         samples = 1068;
981                                 break;
982                         default:
983                                 samples = 0;
984                 }
985         }
986         else if ( fps != 0 )
987         {
988                 samples = frequency / fps;
989         }
990
991         return samples;
992 }