]> git.sesse.net Git - mlt/blob - src/framework/mlt_frame.c
These get/set position calls are unnecessary.
[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 /** Constructor for a frame.
35 */
36
37 mlt_frame mlt_frame_init( mlt_service service )
38 {
39         // Allocate a frame
40         mlt_frame this = calloc( sizeof( struct mlt_frame_s ), 1 );
41
42         if ( this != NULL )
43         {
44                 mlt_profile profile = mlt_service_profile( service );
45
46                 // Initialise the properties
47                 mlt_properties properties = &this->parent;
48                 mlt_properties_init( properties, this );
49
50                 // Set default properties on the frame
51                 mlt_properties_set_position( properties, "_position", 0.0 );
52                 mlt_properties_set_data( properties, "image", NULL, 0, NULL, NULL );
53                 mlt_properties_set_int( properties, "width", profile? profile->width : 720 );
54                 mlt_properties_set_int( properties, "height", profile? profile->height : 576 );
55                 mlt_properties_set_int( properties, "normalised_width", profile? profile->width : 720 );
56                 mlt_properties_set_int( properties, "normalised_height", profile? profile->height : 576 );
57                 mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( NULL ) );
58                 mlt_properties_set_data( properties, "audio", NULL, 0, NULL, NULL );
59                 mlt_properties_set_data( properties, "alpha", NULL, 0, NULL, NULL );
60
61                 // Construct stacks for frames and methods
62                 this->stack_image = mlt_deque_init( );
63                 this->stack_audio = mlt_deque_init( );
64                 this->stack_service = mlt_deque_init( );
65         }
66
67         return this;
68 }
69
70 /** Fetch the frames properties.
71 */
72
73 mlt_properties mlt_frame_properties( mlt_frame this )
74 {
75         return this != NULL ? &this->parent : NULL;
76 }
77
78 /** Check if we have a way to derive something other than a test card.
79 */
80
81 int mlt_frame_is_test_card( mlt_frame this )
82 {
83         return mlt_deque_count( this->stack_image ) == 0 || mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "test_image" );
84 }
85
86 /** Check if we have a way to derive something other than test audio.
87 */
88
89 int mlt_frame_is_test_audio( mlt_frame this )
90 {
91         return mlt_deque_count( this->stack_audio ) == 0 || mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "test_audio" );
92 }
93
94 /** Get the aspect ratio of the frame.
95 */
96
97 double mlt_frame_get_aspect_ratio( mlt_frame this )
98 {
99         return mlt_properties_get_double( MLT_FRAME_PROPERTIES( this ), "aspect_ratio" );
100 }
101
102 /** Set the aspect ratio of the frame.
103 */
104
105 int mlt_frame_set_aspect_ratio( mlt_frame this, double value )
106 {
107         return mlt_properties_set_double( MLT_FRAME_PROPERTIES( this ), "aspect_ratio", value );
108 }
109
110 /** Get the position of this frame.
111 */
112
113 mlt_position mlt_frame_get_position( mlt_frame this )
114 {
115         int pos = mlt_properties_get_position( MLT_FRAME_PROPERTIES( this ), "_position" );
116         return pos < 0 ? 0 : pos;
117 }
118
119 /** Set the position of this frame.
120 */
121
122 int mlt_frame_set_position( mlt_frame this, mlt_position value )
123 {
124         return mlt_properties_set_position( MLT_FRAME_PROPERTIES( this ), "_position", value );
125 }
126
127 /** Stack a get_image callback.
128 */
129
130 int mlt_frame_push_get_image( mlt_frame this, mlt_get_image get_image )
131 {
132         return mlt_deque_push_back( this->stack_image, get_image );
133 }
134
135 /** Pop a get_image callback.
136 */
137
138 mlt_get_image mlt_frame_pop_get_image( mlt_frame this )
139 {
140         return mlt_deque_pop_back( this->stack_image );
141 }
142
143 /** Push a frame.
144 */
145
146 int mlt_frame_push_frame( mlt_frame this, mlt_frame that )
147 {
148         return mlt_deque_push_back( this->stack_image, that );
149 }
150
151 /** Pop a frame.
152 */
153
154 mlt_frame mlt_frame_pop_frame( mlt_frame this )
155 {
156         return mlt_deque_pop_back( this->stack_image );
157 }
158
159 /** Push a service.
160 */
161
162 int mlt_frame_push_service( mlt_frame this, void *that )
163 {
164         return mlt_deque_push_back( this->stack_image, that );
165 }
166
167 /** Pop a service.
168 */
169
170 void *mlt_frame_pop_service( mlt_frame this )
171 {
172         return mlt_deque_pop_back( this->stack_image );
173 }
174
175 /** Push a service.
176 */
177
178 int mlt_frame_push_service_int( mlt_frame this, int that )
179 {
180         return mlt_deque_push_back_int( this->stack_image, that );
181 }
182
183 /** Pop a service.
184 */
185
186 int mlt_frame_pop_service_int( mlt_frame this )
187 {
188         return mlt_deque_pop_back_int( this->stack_image );
189 }
190
191 /** Push an audio item on the stack.
192 */
193
194 int mlt_frame_push_audio( mlt_frame this, void *that )
195 {
196         return mlt_deque_push_back( this->stack_audio, that );
197 }
198
199 /** Pop an audio item from the stack
200 */
201
202 void *mlt_frame_pop_audio( mlt_frame this )
203 {
204         return mlt_deque_pop_back( this->stack_audio );
205 }
206
207 /** Return the service stack
208 */
209
210 mlt_deque mlt_frame_service_stack( mlt_frame this )
211 {
212         return this->stack_service;
213 }
214
215 /** Replace image stack with the information provided.
216
217         This might prove to be unreliable and restrictive - the idea is that a transition
218         which normally uses two images may decide to only use the b frame (ie: in the case
219         of a composite where the b frame completely obscures the a frame).
220
221         The image must be writable and the destructor for the image itself must be taken
222         care of on another frame and that frame cannot have a replace applied to it...
223         Further it assumes that no alpha mask is in use.
224
225         For these reasons, it can only be used in a specific situation - when you have
226         multiple tracks each with their own transition and these transitions are applied
227         in a strictly reversed order (ie: highest numbered [lowest track] is processed
228         first).
229
230         More reliable approach - the cases should be detected during the process phase
231         and the upper tracks should simply not be invited to stack...
232 */
233
234 void mlt_frame_replace_image( mlt_frame this, uint8_t *image, mlt_image_format format, int width, int height )
235 {
236         // Remove all items from the stack
237         while( mlt_deque_pop_back( this->stack_image ) ) ;
238
239         // Update the information
240         mlt_properties_set_data( MLT_FRAME_PROPERTIES( this ), "image", image, 0, NULL, NULL );
241         mlt_properties_set_int( MLT_FRAME_PROPERTIES( this ), "width", width );
242         mlt_properties_set_int( MLT_FRAME_PROPERTIES( this ), "height", height );
243         mlt_properties_set_int( MLT_FRAME_PROPERTIES( this ), "format", format );
244         this->get_alpha_mask = NULL;
245 }
246
247 const char * mlt_image_format_name( mlt_image_format format )
248 {
249         switch ( format )
250         {
251                 case mlt_image_none:    return "none";
252                 case mlt_image_rgb24:   return "rgb24";
253                 case mlt_image_rgb24a:  return "rgb24a";
254                 case mlt_image_yuv422:  return "yuv422";
255                 case mlt_image_yuv420p: return "yuv420p";
256                 case mlt_image_opengl:  return "opengl";
257         }
258         return "invalid";
259 }
260
261 /** Get the image associated to the frame.
262 */
263
264 int mlt_frame_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
265 {
266         mlt_properties properties = MLT_FRAME_PROPERTIES( this );
267         mlt_get_image get_image = mlt_frame_pop_get_image( this );
268         mlt_producer producer = mlt_properties_get_data( properties, "test_card_producer", NULL );
269         mlt_image_format requested_format = *format;
270         int error = 0;
271
272         if ( get_image )
273         {
274                 mlt_properties_set_int( properties, "image_count", mlt_properties_get_int( properties, "image_count" ) - 1 );
275                 error = get_image( this, buffer, format, width, height, writable );
276                 mlt_properties_set_int( properties, "width", *width );
277                 mlt_properties_set_int( properties, "height", *height );
278                 mlt_properties_set_int( properties, "format", *format );
279                 if ( this->convert_image )
280                         this->convert_image( this, buffer, format, requested_format );
281         }
282         else if ( mlt_properties_get_data( properties, "image", NULL ) )
283         {
284                 *format = mlt_properties_get_int( properties, "format" );
285                 *buffer = mlt_properties_get_data( properties, "image", NULL );
286                 *width = mlt_properties_get_int( properties, "width" );
287                 *height = mlt_properties_get_int( properties, "height" );
288                 if ( this->convert_image )
289                         this->convert_image( this, buffer, format, requested_format );
290         }
291         else if ( producer )
292         {
293                 mlt_frame test_frame = NULL;
294                 mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &test_frame, 0 );
295                 if ( test_frame )
296                 {
297                         mlt_properties test_properties = MLT_FRAME_PROPERTIES( test_frame );
298                         mlt_properties_set_double( test_properties, "consumer_aspect_ratio", mlt_properties_get_double( properties, "consumer_aspect_ratio" ) );
299                         mlt_properties_set( test_properties, "rescale.interp", mlt_properties_get( properties, "rescale.interp" ) );
300                         mlt_frame_get_image( test_frame, buffer, format, width, height, writable );
301                         mlt_properties_set_data( properties, "test_card_frame", test_frame, 0, ( mlt_destructor )mlt_frame_close, NULL );
302                         mlt_properties_set_double( properties, "aspect_ratio", mlt_frame_get_aspect_ratio( test_frame ) );
303 //                      mlt_properties_set_data( properties, "image", *buffer, *width * *height * 2, NULL, NULL );
304 //                      mlt_properties_set_int( properties, "width", *width );
305 //                      mlt_properties_set_int( properties, "height", *height );
306 //                      mlt_properties_set_int( properties, "format", *format );
307                 }
308                 else
309                 {
310                         mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL );
311                         mlt_frame_get_image( this, buffer, format, width, height, writable );
312                 }
313         }
314         else
315         {
316                 register uint8_t *p;
317                 register uint8_t *q;
318                 int size = 0;
319
320                 *width = *width == 0 ? 720 : *width;
321                 *height = *height == 0 ? 576 : *height;
322                 size = *width * *height;
323
324                 mlt_properties_set_int( properties, "format", *format );
325                 mlt_properties_set_int( properties, "width", *width );
326                 mlt_properties_set_int( properties, "height", *height );
327                 mlt_properties_set_int( properties, "aspect_ratio", 0 );
328
329                 switch( *format )
330                 {
331                         case mlt_image_none:
332                                 size = 0;
333                                 *buffer = NULL;
334                                 break;
335                         case mlt_image_rgb24:
336                                 size *= 3;
337                                 size += *width * 3;
338                                 *buffer = mlt_pool_alloc( size );
339                                 if ( *buffer )
340                                         memset( *buffer, 255, size );
341                                 break;
342                         case mlt_image_rgb24a:
343                         case mlt_image_opengl:
344                                 size *= 4;
345                                 size += *width * 4;
346                                 *buffer = mlt_pool_alloc( size );
347                                 if ( *buffer )
348                                         memset( *buffer, 255, size );
349                                 break;
350                         case mlt_image_yuv422:
351                                 size *= 2;
352                                 size += *width * 2;
353                                 *buffer = mlt_pool_alloc( size );
354                                 p = *buffer;
355                                 q = p + size;
356                                 while ( p != NULL && p != q )
357                                 {
358                                         *p ++ = 235;
359                                         *p ++ = 128;
360                                 }
361                                 break;
362                         case mlt_image_yuv420p:
363                                 size = size * 3 / 2;
364                                 *buffer = mlt_pool_alloc( size );
365                                 if ( *buffer )
366                                         memset( *buffer, 255, size );
367                                 break;
368                 }
369
370                 mlt_properties_set_data( properties, "image", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL );
371                 mlt_properties_set_int( properties, "test_image", 1 );
372         }
373
374         mlt_properties_set_int( properties, "scaled_width", *width );
375         mlt_properties_set_int( properties, "scaled_height", *height );
376
377         return error;
378 }
379
380 uint8_t *mlt_frame_get_alpha_mask( mlt_frame this )
381 {
382         uint8_t *alpha = NULL;
383         if ( this != NULL )
384         {
385                 if ( this->get_alpha_mask != NULL )
386                         alpha = this->get_alpha_mask( this );
387                 if ( alpha == NULL )
388                         alpha = mlt_properties_get_data( &this->parent, "alpha", NULL );
389                 if ( alpha == NULL )
390                 {
391                         int size = mlt_properties_get_int( &this->parent, "scaled_width" ) * mlt_properties_get_int( &this->parent, "scaled_height" );
392                         alpha = mlt_pool_alloc( size );
393                         memset( alpha, 255, size );
394                         mlt_properties_set_data( &this->parent, "alpha", alpha, size, mlt_pool_release, NULL );
395                 }
396         }
397         return alpha;
398 }
399
400 const char * mlt_audio_format_name( mlt_audio_format format )
401 {
402         switch ( format )
403         {
404                 case mlt_audio_none:   return "none";
405                 case mlt_audio_s16:    return "s16";
406                 case mlt_audio_s32:    return "s32";
407                 case mlt_audio_float:  return "float";
408         }
409         return "invalid";
410 }
411
412 int mlt_frame_get_audio( mlt_frame this, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
413 {
414         mlt_get_audio get_audio = mlt_frame_pop_audio( this );
415         mlt_properties properties = MLT_FRAME_PROPERTIES( this );
416         int hide = mlt_properties_get_int( properties, "test_audio" );
417         mlt_audio_format requested_format = *format;
418
419         if ( hide == 0 && get_audio != NULL )
420         {
421                 get_audio( this, buffer, format, frequency, channels, samples );
422                 mlt_properties_set_int( properties, "audio_frequency", *frequency );
423                 mlt_properties_set_int( properties, "audio_channels", *channels );
424                 mlt_properties_set_int( properties, "audio_samples", *samples );
425                 mlt_properties_set_int( properties, "audio_format", *format );
426                 if ( this->convert_audio )
427                         this->convert_audio( this, buffer, format, requested_format );
428         }
429         else if ( mlt_properties_get_data( properties, "audio", NULL ) )
430         {
431                 *buffer = mlt_properties_get_data( properties, "audio", NULL );
432                 *format = mlt_properties_get_int( properties, "audio_format" );
433                 *frequency = mlt_properties_get_int( properties, "audio_frequency" );
434                 *channels = mlt_properties_get_int( properties, "audio_channels" );
435                 *samples = mlt_properties_get_int( properties, "audio_samples" );
436                 if ( this->convert_audio )
437                         this->convert_audio( this, buffer, format, requested_format );
438         }
439         else
440         {
441                 int size = 0;
442                 *samples = *samples <= 0 ? 1920 : *samples;
443                 *channels = *channels <= 0 ? 2 : *channels;
444                 *frequency = *frequency <= 0 ? 48000 : *frequency;
445                 mlt_properties_set_int( properties, "audio_frequency", *frequency );
446                 mlt_properties_set_int( properties, "audio_channels", *channels );
447                 mlt_properties_set_int( properties, "audio_samples", *samples );
448                 mlt_properties_set_int( properties, "audio_format", *format );
449
450                 switch( *format )
451                 {
452                         case mlt_image_none:
453                                 size = 0;
454                                 *buffer = NULL;
455                                 break;
456                         case mlt_audio_s16:
457                                 size = *samples * *channels * sizeof( int16_t );
458                                 break;
459                         case mlt_audio_s32:
460                                 size = *samples * *channels * sizeof( int32_t );
461                                 break;
462                         case mlt_audio_float:
463                                 size = *samples * *channels * sizeof( float );
464                                 break;
465                 }
466                 if ( size )
467                         *buffer = mlt_pool_alloc( size );
468                 if ( *buffer )
469                         memset( *buffer, 0, size );
470                 mlt_properties_set_data( properties, "audio", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL );
471                 mlt_properties_set_int( properties, "test_audio", 1 );
472         }
473
474         // TODO: This does not belong here
475         if ( *format == mlt_audio_s16 && mlt_properties_get( properties, "meta.volume" ) )
476         {
477                 double value = mlt_properties_get_double( properties, "meta.volume" );
478
479                 if ( value == 0.0 )
480                 {
481                         memset( *buffer, 0, *samples * *channels * 2 );
482                 }
483                 else if ( value != 1.0 )
484                 {
485                         int total = *samples * *channels;
486                         int16_t *p = *buffer;
487                         while ( total -- )
488                         {
489                                 *p = *p * value;
490                                 p ++;
491                         }
492                 }
493
494                 mlt_properties_set( properties, "meta.volume", NULL );
495         }
496
497         return 0;
498 }
499
500 int mlt_frame_set_audio( mlt_frame this, void *buffer, mlt_audio_format format, int size, mlt_destructor destructor )
501 {
502         mlt_properties_set_int( MLT_FRAME_PROPERTIES( this ), "audio_format", format );
503         return mlt_properties_set_data( MLT_FRAME_PROPERTIES( this ), "audio", buffer, size, destructor, NULL );
504 }
505
506 unsigned char *mlt_frame_get_waveform( mlt_frame this, int w, int h )
507 {
508         int16_t *pcm = NULL;
509         mlt_properties properties = MLT_FRAME_PROPERTIES( this );
510         mlt_audio_format format = mlt_audio_s16;
511         int frequency = 32000; // lower frequency available?
512         int channels = 2;
513         double fps = mlt_profile_fps( NULL );
514         int samples = mlt_sample_calculator( fps, frequency, mlt_frame_get_position( this ) );
515
516         // Get the pcm data
517         mlt_frame_get_audio( this, (void**)&pcm, &format, &frequency, &channels, &samples );
518
519         // Make an 8-bit buffer large enough to hold rendering
520         int size = w * h;
521         unsigned char *bitmap = ( unsigned char* )mlt_pool_alloc( size );
522         if ( bitmap != NULL )
523                 memset( bitmap, 0, size );
524         mlt_properties_set_data( properties, "waveform", bitmap, size, ( mlt_destructor )mlt_pool_release, NULL );
525
526         // Render vertical lines
527         int16_t *ubound = pcm + samples * channels;
528         int skip = samples / w - 1;
529         int i, j, k;
530
531         // Iterate sample stream and along x coordinate
532         for ( i = 0; i < w && pcm < ubound; i++ )
533         {
534                 // pcm data has channels interleaved
535                 for ( j = 0; j < channels; j++ )
536                 {
537                         // Determine sample's magnitude from 2s complement;
538                         int pcm_magnitude = *pcm < 0 ? ~(*pcm) + 1 : *pcm;
539                         // The height of a line is the ratio of the magnitude multiplied by
540                         // half the vertical resolution
541                         int height = ( int )( ( double )( pcm_magnitude ) / 32768 * h / 2 );
542                         // Determine the starting y coordinate - left channel above center,
543                         // right channel below - currently assumes 2 channels
544                         int displacement = ( h / 2 ) - ( 1 - j ) * height;
545                         // Position buffer pointer using y coordinate, stride, and x coordinate
546                         unsigned char *p = &bitmap[ i + displacement * w ];
547
548                         // Draw vertical line
549                         for ( k = 0; k < height; k++ )
550                                 p[ w * k ] = 0xFF;
551
552                         pcm++;
553                 }
554                 pcm += skip * channels;
555         }
556
557         return bitmap;
558 }
559
560 mlt_producer mlt_frame_get_original_producer( mlt_frame this )
561 {
562         if ( this != NULL )
563                 return mlt_properties_get_data( MLT_FRAME_PROPERTIES( this ), "_producer", NULL );
564         return NULL;
565 }
566
567 void mlt_frame_close( mlt_frame this )
568 {
569         if ( this != NULL && mlt_properties_dec_ref( MLT_FRAME_PROPERTIES( this ) ) <= 0 )
570         {
571                 mlt_deque_close( this->stack_image );
572                 mlt_deque_close( this->stack_audio );
573                 while( mlt_deque_peek_back( this->stack_service ) )
574                         mlt_service_close( mlt_deque_pop_back( this->stack_service ) );
575                 mlt_deque_close( this->stack_service );
576                 mlt_properties_close( &this->parent );
577                 free( this );
578         }
579 }
580
581 /***** convenience functions *****/
582
583 /* Will this break when mlt_position is converted to double? -Zach */
584 int mlt_sample_calculator( float fps, int frequency, int64_t position )
585 {
586         int samples = 0;
587
588         if ( fps )
589         {
590                 /* Compute the cumulative number of samples until the start of this frame and the
591                 cumulative number of samples until the start of the next frame. Round each to the
592                 nearest integer and take the difference to determine the number of samples in
593                 this frame.
594
595                 This approach should prevent rounding errors that can accumulate over a large number
596                 of frames causing A/V sync problems. */
597
598                 int64_t samples_at_this =
599                         (int64_t)( (double) position * (double) frequency / (double) fps +
600                         ( position < 0 ? -0.5 : 0.5 ) );
601                 int64_t samples_at_next =
602                         (int64_t)( (double) (position + 1) * (double) frequency / (double) fps +
603                         ( position < 0 ? -0.5 : 0.5 ) );
604                 samples = (int)( samples_at_next - samples_at_this );
605         }
606
607         return samples;
608 }
609
610 int64_t mlt_sample_calculator_to_now( float fps, int frequency, int64_t frame )
611 {
612         int64_t samples = 0;
613
614         if ( fps )
615         {
616                 samples = (int64_t)( (double) frame * (double) frequency / (double) fps +
617                         ( frame < 0 ? -0.5 : 0.5 ) );
618         }
619
620         return samples;
621 }