1 /**
2 * \file mlt_frame.c
3 * \brief interface for all frame classes
4 * \see mlt_frame_s
5 *
6 * Copyright (C) 2003-2019 Meltytech, LLC
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include "mlt_frame.h"
24 #include "mlt_image.h"
25 #include "mlt_producer.h"
26 #include "mlt_factory.h"
27 #include "mlt_profile.h"
28 #include "mlt_log.h"
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 /** Construct a frame object.
35 *
36 * \public \memberof mlt_frame_s
37 * \param service the pointer to any service that can provide access to the profile
38 * \return a frame object on success or NULL if there was an allocation error
39 */
40
mlt_frame_init(mlt_service service)41 mlt_frame mlt_frame_init( mlt_service service )
42 {
43 // Allocate a frame
44 mlt_frame self = calloc( 1, sizeof( struct mlt_frame_s ) );
45
46 if ( self != NULL )
47 {
48 mlt_profile profile = mlt_service_profile( service );
49
50 // Initialise the properties
51 mlt_properties properties = &self->parent;
52 mlt_properties_init( properties, self );
53
54 // Set default properties on the frame
55 mlt_properties_set_position( properties, "_position", 0.0 );
56 mlt_properties_set_data( properties, "image", NULL, 0, NULL, NULL );
57 mlt_properties_set_int( properties, "width", profile? profile->width : 720 );
58 mlt_properties_set_int( properties, "height", profile? profile->height : 576 );
59 mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( NULL ) );
60 mlt_properties_set_data( properties, "audio", NULL, 0, NULL, NULL );
61 mlt_properties_set_data( properties, "alpha", NULL, 0, NULL, NULL );
62
63 // Construct stacks for frames and methods
64 self->stack_image = mlt_deque_init( );
65 self->stack_audio = mlt_deque_init( );
66 self->stack_service = mlt_deque_init( );
67 }
68
69 return self;
70 }
71
72 /** Get a frame's properties.
73 *
74 * \public \memberof mlt_frame_s
75 * \param self a frame
76 * \return the frame's properties or NULL if an invalid frame is supplied
77 */
78
mlt_frame_properties(mlt_frame self)79 mlt_properties mlt_frame_properties( mlt_frame self )
80 {
81 return self != NULL ? &self->parent : NULL;
82 }
83
84 /** Determine if the frame will produce a test card image.
85 *
86 * \public \memberof mlt_frame_s
87 * \param self a frame
88 * \return true (non-zero) if this will produce from a test card
89 */
90
mlt_frame_is_test_card(mlt_frame self)91 int mlt_frame_is_test_card( mlt_frame self )
92 {
93 mlt_properties properties = MLT_FRAME_PROPERTIES( self );
94 return ( mlt_deque_count( self->stack_image ) == 0
95 && !mlt_properties_get_data( properties, "image", NULL ) )
96 || mlt_properties_get_int( properties, "test_image" );
97 }
98
99 /** Determine if the frame will produce audio from a test card.
100 *
101 * \public \memberof mlt_frame_s
102 * \param self a frame
103 * \return true (non-zero) if this will produce from a test card
104 */
105
mlt_frame_is_test_audio(mlt_frame self)106 int mlt_frame_is_test_audio( mlt_frame self )
107 {
108 mlt_properties properties = MLT_FRAME_PROPERTIES( self );
109 return ( mlt_deque_count( self->stack_audio ) == 0
110 && !mlt_properties_get_data( properties, "audio", NULL ) )
111 || mlt_properties_get_int( properties, "test_audio" );
112 }
113
114 /** Get the sample aspect ratio of the frame.
115 *
116 * \public \memberof mlt_frame_s
117 * \param self a frame
118 * \return the aspect ratio
119 */
120
mlt_frame_get_aspect_ratio(mlt_frame self)121 double mlt_frame_get_aspect_ratio( mlt_frame self )
122 {
123 return mlt_properties_get_double( MLT_FRAME_PROPERTIES( self ), "aspect_ratio" );
124 }
125
126 /** Set the sample aspect ratio of the frame.
127 *
128 * \public \memberof mlt_frame_s
129 * \param self a frame
130 * \param value the new image sample aspect ratio
131 * \return true if error
132 */
133
mlt_frame_set_aspect_ratio(mlt_frame self,double value)134 int mlt_frame_set_aspect_ratio( mlt_frame self, double value )
135 {
136 return mlt_properties_set_double( MLT_FRAME_PROPERTIES( self ), "aspect_ratio", value );
137 }
138
139 /** Get the time position of this frame.
140 *
141 * This position is not necessarily the position as the original
142 * producer knows it. It could be the position that the playlist,
143 * multitrack, or tractor producer set.
144 *
145 * \public \memberof mlt_frame_s
146 * \param self a frame
147 * \return the position
148 * \see mlt_frame_original_position
149 */
150
mlt_frame_get_position(mlt_frame self)151 mlt_position mlt_frame_get_position( mlt_frame self )
152 {
153 int pos = mlt_properties_get_position( MLT_FRAME_PROPERTIES( self ), "_position" );
154 return pos < 0 ? 0 : pos;
155 }
156
157 /** Get the original time position of this frame.
158 *
159 * This is the position that the original producer set on the frame.
160 *
161 * \public \memberof mlt_frame_s
162 * \param self a frame
163 * \return the position
164 */
165
mlt_frame_original_position(mlt_frame self)166 mlt_position mlt_frame_original_position( mlt_frame self )
167 {
168 int pos = mlt_properties_get_position( MLT_FRAME_PROPERTIES( self ), "original_position" );
169 return pos < 0 ? 0 : pos;
170 }
171
172 /** Set the time position of this frame.
173 *
174 * \public \memberof mlt_frame_s
175 * \param self a frame
176 * \param value the position
177 * \return true if error
178 */
179
mlt_frame_set_position(mlt_frame self,mlt_position value)180 int mlt_frame_set_position( mlt_frame self, mlt_position value )
181 {
182 // Only set the original_position the first time.
183 if ( ! mlt_properties_get( MLT_FRAME_PROPERTIES( self ), "original_position" ) )
184 mlt_properties_set_position( MLT_FRAME_PROPERTIES( self ), "original_position", value );
185 return mlt_properties_set_position( MLT_FRAME_PROPERTIES( self ), "_position", value );
186 }
187
188 /** Stack a get_image callback.
189 *
190 * \public \memberof mlt_frame_s
191 * \param self a frame
192 * \param get_image the get_image callback
193 * \return true if error
194 */
195
mlt_frame_push_get_image(mlt_frame self,mlt_get_image get_image)196 int mlt_frame_push_get_image( mlt_frame self, mlt_get_image get_image )
197 {
198 return mlt_deque_push_back( self->stack_image, get_image );
199 }
200
201 /** Pop a get_image callback.
202 *
203 * \public \memberof mlt_frame_s
204 * \param self a frame
205 * \return the get_image callback
206 */
207
mlt_frame_pop_get_image(mlt_frame self)208 mlt_get_image mlt_frame_pop_get_image( mlt_frame self )
209 {
210 return mlt_deque_pop_back( self->stack_image );
211 }
212
213 /** Push a frame.
214 *
215 * \public \memberof mlt_frame_s
216 * \param self a frame
217 * \param that the frame to push onto \p self
218 * \return true if error
219 */
220
mlt_frame_push_frame(mlt_frame self,mlt_frame that)221 int mlt_frame_push_frame( mlt_frame self, mlt_frame that )
222 {
223 return mlt_deque_push_back( self->stack_image, that );
224 }
225
226 /** Pop a frame.
227 *
228 * \public \memberof mlt_frame_s
229 * \param self a frame
230 * \return a frame that was previously pushed
231 */
232
mlt_frame_pop_frame(mlt_frame self)233 mlt_frame mlt_frame_pop_frame( mlt_frame self )
234 {
235 return mlt_deque_pop_back( self->stack_image );
236 }
237
238 /** Push a service.
239 *
240 * \public \memberof mlt_frame_s
241 * \param self a frame
242 * \param that an opaque pointer
243 * \return true if error
244 */
245
mlt_frame_push_service(mlt_frame self,void * that)246 int mlt_frame_push_service( mlt_frame self, void *that )
247 {
248 return mlt_deque_push_back( self->stack_image, that );
249 }
250
251 /** Pop a service.
252 *
253 * \public \memberof mlt_frame_s
254 * \param self a frame
255 * \return an opaque pointer to something previously pushed
256 */
257
mlt_frame_pop_service(mlt_frame self)258 void *mlt_frame_pop_service( mlt_frame self )
259 {
260 return mlt_deque_pop_back( self->stack_image );
261 }
262
263 /** Push a number.
264 *
265 * \public \memberof mlt_frame_s
266 * \param self a frame
267 * \param that an integer
268 * \return true if error
269 */
270
mlt_frame_push_service_int(mlt_frame self,int that)271 int mlt_frame_push_service_int( mlt_frame self, int that )
272 {
273 return mlt_deque_push_back_int( self->stack_image, that );
274 }
275
276 /** Pop a number.
277 *
278 * \public \memberof mlt_frame_s
279 * \param self a frame
280 * \return an integer that was previously pushed
281 */
282
mlt_frame_pop_service_int(mlt_frame self)283 int mlt_frame_pop_service_int( mlt_frame self )
284 {
285 return mlt_deque_pop_back_int( self->stack_image );
286 }
287
288 /** Push an audio item on the stack.
289 *
290 * \public \memberof mlt_frame_s
291 * \param self a frame
292 * \param that an opaque pointer
293 * \return true if error
294 */
295
mlt_frame_push_audio(mlt_frame self,void * that)296 int mlt_frame_push_audio( mlt_frame self, void *that )
297 {
298 return mlt_deque_push_back( self->stack_audio, that );
299 }
300
301 /** Pop an audio item from the stack
302 *
303 * \public \memberof mlt_frame_s
304 * \param self a frame
305 * \return an opaque pointer to something that was pushed onto the frame's audio stack
306 */
307
mlt_frame_pop_audio(mlt_frame self)308 void *mlt_frame_pop_audio( mlt_frame self )
309 {
310 return mlt_deque_pop_back( self->stack_audio );
311 }
312
313 /** Return the service stack
314 *
315 * \public \memberof mlt_frame_s
316 * \param self a frame
317 * \return the service stack
318 */
319
mlt_frame_service_stack(mlt_frame self)320 mlt_deque mlt_frame_service_stack( mlt_frame self )
321 {
322 return self->stack_service;
323 }
324
325 /** Set a new image on the frame.
326 *
327 * \public \memberof mlt_frame_s
328 * \param self a frame
329 * \param image a pointer to the raw image data
330 * \param size the size of the image data in bytes (optional)
331 * \param destroy a function to deallocate \p image when the frame is closed (optional)
332 * \return true if error
333 */
334
mlt_frame_set_image(mlt_frame self,uint8_t * image,int size,mlt_destructor destroy)335 int mlt_frame_set_image( mlt_frame self, uint8_t *image, int size, mlt_destructor destroy )
336 {
337 return mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "image", image, size, destroy, NULL );
338 }
339
340 /** Set a new alpha channel on the frame.
341 *
342 * \public \memberof mlt_frame_s
343 * \param self a frame
344 * \param alpha a pointer to the alpha channel
345 * \param size the size of the alpha channel in bytes (optional)
346 * \param destroy a function to deallocate \p alpha when the frame is closed (optional)
347 * \return true if error
348 */
349
mlt_frame_set_alpha(mlt_frame self,uint8_t * alpha,int size,mlt_destructor destroy)350 int mlt_frame_set_alpha( mlt_frame self, uint8_t *alpha, int size, mlt_destructor destroy )
351 {
352 return mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "alpha", alpha, size, destroy, NULL );
353 }
354
355 /** Replace image stack with the information provided.
356 *
357 * This might prove to be unreliable and restrictive - the idea is that a transition
358 * which normally uses two images may decide to only use the b frame (ie: in the case
359 * of a composite where the b frame completely obscures the a frame).
360 *
361 * The image must be writable and the destructor for the image itself must be taken
362 * care of on another frame and that frame cannot have a replace applied to it...
363 * Further it assumes that no alpha mask is in use.
364 *
365 * For these reasons, it can only be used in a specific situation - when you have
366 * multiple tracks each with their own transition and these transitions are applied
367 * in a strictly reversed order (ie: highest numbered [lowest track] is processed
368 * first).
369 *
370 * More reliable approach - the cases should be detected during the process phase
371 * and the upper tracks should simply not be invited to stack...
372 *
373 * \public \memberof mlt_frame_s
374 * \param self a frame
375 * \param image a new image
376 * \param format the image format
377 * \param width the width of the new image
378 * \param height the height of the new image
379 */
380
mlt_frame_replace_image(mlt_frame self,uint8_t * image,mlt_image_format format,int width,int height)381 void mlt_frame_replace_image( mlt_frame self, uint8_t *image, mlt_image_format format, int width, int height )
382 {
383 // Remove all items from the stack
384 while( mlt_deque_pop_back( self->stack_image ) ) ;
385
386 // Update the information
387 mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "image", image, 0, NULL, NULL );
388 mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "width", width );
389 mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "height", height );
390 mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "format", format );
391 }
392
generate_test_image(mlt_properties properties,uint8_t ** buffer,mlt_image_format * format,int * width,int * height,int writable)393 static int generate_test_image( mlt_properties properties, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
394 {
395 mlt_producer producer = mlt_properties_get_data( properties, "test_card_producer", NULL );
396 mlt_image_format requested_format = *format;
397 int error = 1;
398
399 if ( producer )
400 {
401 mlt_frame test_frame = NULL;
402 mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &test_frame, 0 );
403 if ( test_frame )
404 {
405 mlt_properties test_properties = MLT_FRAME_PROPERTIES( test_frame );
406 mlt_properties_set_data( properties, "test_card_frame", test_frame, 0, ( mlt_destructor )mlt_frame_close, NULL );
407 mlt_properties_set( test_properties, "rescale.interp", mlt_properties_get( properties, "rescale.interp" ) );
408 error = mlt_frame_get_image( test_frame, buffer, format, width, height, writable );
409 if ( !error && buffer && *buffer )
410 {
411 mlt_properties_set_double( properties, "aspect_ratio", mlt_frame_get_aspect_ratio( test_frame ) );
412 mlt_properties_set_int( properties, "width", *width );
413 mlt_properties_set_int( properties, "height", *height );
414 if ( test_frame->convert_image && requested_format != mlt_image_none )
415 test_frame->convert_image( test_frame, buffer, format, requested_format );
416 mlt_properties_set_int( properties, "format", *format );
417 }
418 }
419 else
420 {
421 mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL );
422 }
423 }
424 if ( error && buffer )
425 {
426 *width = *width == 0 ? 720 : *width;
427 *height = *height == 0 ? 576 : *height;
428 switch( *format )
429 {
430 case mlt_image_rgb:
431 case mlt_image_rgba:
432 case mlt_image_yuv422:
433 case mlt_image_yuv422p16:
434 case mlt_image_yuv420p:
435 break;
436 case mlt_image_none:
437 case mlt_image_movit:
438 case mlt_image_opengl_texture:
439 *format = mlt_image_yuv422;
440 break;
441 }
442
443 struct mlt_image_s img;
444 mlt_image_set_values( &img, NULL, *format, *width, *height );
445 mlt_image_alloc_data( &img );
446 mlt_image_fill_black( &img );
447
448 *buffer = img.data;
449 mlt_properties_set_int( properties, "format", *format );
450 mlt_properties_set_int( properties, "width", *width );
451 mlt_properties_set_int( properties, "height", *height );
452 mlt_properties_set_double( properties, "aspect_ratio", 1.0 );
453 mlt_properties_set_data( properties, "image", *buffer, 0, img.release_data, NULL );
454 mlt_properties_set_int( properties, "test_image", 1 );
455 error = 0;
456 }
457 return error;
458 }
459
460
461 /** Get the image associated to the frame.
462 *
463 * You should express the desired format, width, and height as inputs. As long
464 * as the loader producer was used to generate this or the imageconvert filter
465 * was attached, then you will get the image back in the format you desire.
466 * However, you do not always get the width and height you request depending
467 * on properties and filters. You do not need to supply a pre-allocated
468 * buffer, but you should always supply the desired image format.
469 *
470 * \public \memberof mlt_frame_s
471 * \param self a frame
472 * \param[out] buffer an image buffer
473 * \param[in,out] format the image format
474 * \param[in,out] width the horizontal size in pixels
475 * \param[in,out] height the vertical size in pixels
476 * \param writable whether or not you will need to be able to write to the memory returned in \p buffer
477 * \return true if error
478 * \todo Better describe the width and height as inputs.
479 */
480
mlt_frame_get_image(mlt_frame self,uint8_t ** buffer,mlt_image_format * format,int * width,int * height,int writable)481 int mlt_frame_get_image( mlt_frame self, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
482 {
483 mlt_properties properties = MLT_FRAME_PROPERTIES( self );
484 mlt_get_image get_image = mlt_frame_pop_get_image( self );
485 mlt_image_format requested_format = *format;
486 int error = 0;
487
488 if ( get_image )
489 {
490 mlt_properties_set_int( properties, "image_count", mlt_properties_get_int( properties, "image_count" ) - 1 );
491 error = get_image( self, buffer, format, width, height, writable );
492 if ( !error && buffer && *buffer )
493 {
494 mlt_properties_set_int( properties, "width", *width );
495 mlt_properties_set_int( properties, "height", *height );
496 if ( self->convert_image && requested_format != mlt_image_none )
497 self->convert_image( self, buffer, format, requested_format );
498 mlt_properties_set_int( properties, "format", *format );
499 }
500 else
501 {
502 error = generate_test_image( properties, buffer, format, width, height, writable );
503 }
504 }
505 else if ( mlt_properties_get_data( properties, "image", NULL ) && buffer )
506 {
507 *format = mlt_properties_get_int( properties, "format" );
508 *buffer = mlt_properties_get_data( properties, "image", NULL );
509 *width = mlt_properties_get_int( properties, "width" );
510 *height = mlt_properties_get_int( properties, "height" );
511 if ( self->convert_image && *buffer && requested_format != mlt_image_none )
512 {
513 self->convert_image( self, buffer, format, requested_format );
514 mlt_properties_set_int( properties, "format", *format );
515 }
516 }
517 else
518 {
519 error = generate_test_image( properties, buffer, format, width, height, writable );
520 }
521
522 return error;
523 }
524
525 /** Get the alpha channel associated to the frame (without creating if it has not).
526 *
527 * \public \memberof mlt_frame_s
528 * \param self a frame
529 * \return the alpha channel or NULL
530 */
531
mlt_frame_get_alpha(mlt_frame self)532 uint8_t *mlt_frame_get_alpha( mlt_frame self )
533 {
534 uint8_t *alpha = NULL;
535 if ( self != NULL )
536 {
537 alpha = mlt_properties_get_data( &self->parent, "alpha", NULL );
538 }
539 return alpha;
540 }
541
542 /** Get the audio associated to the frame.
543 *
544 * You should express the desired format, frequency, channels, and samples as inputs. As long
545 * as the loader producer was used to generate this or the audioconvert filter
546 * was attached, then you will get the audio back in the format you desire.
547 * However, you do not always get the channels and samples you request depending
548 * on properties and filters. You do not need to supply a pre-allocated
549 * buffer, but you should always supply the desired audio format.
550 * The audio is always in interleaved format.
551 * You should use the \p mlt_audio_sample_calculator to determine the number of samples you want.
552 *
553 * \public \memberof mlt_frame_s
554 * \param self a frame
555 * \param[out] buffer an audio buffer
556 * \param[in,out] format the audio format
557 * \param[in,out] frequency the sample rate
558 * \param[in,out] channels
559 * \param[in,out] samples the number of samples per frame
560 * \return true if error
561 */
562
mlt_frame_get_audio(mlt_frame self,void ** buffer,mlt_audio_format * format,int * frequency,int * channels,int * samples)563 int mlt_frame_get_audio( mlt_frame self, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
564 {
565 mlt_get_audio get_audio = mlt_frame_pop_audio( self );
566 mlt_properties properties = MLT_FRAME_PROPERTIES( self );
567 int hide = mlt_properties_get_int( properties, "test_audio" );
568 mlt_audio_format requested_format = *format;
569
570 if ( hide == 0 && get_audio != NULL )
571 {
572 get_audio( self, buffer, format, frequency, channels, samples );
573 mlt_properties_set_int( properties, "audio_frequency", *frequency );
574 mlt_properties_set_int( properties, "audio_channels", *channels );
575 mlt_properties_set_int( properties, "audio_samples", *samples );
576 mlt_properties_set_int( properties, "audio_format", *format );
577 if ( self->convert_audio && *buffer && requested_format != mlt_audio_none )
578 self->convert_audio( self, buffer, format, requested_format );
579 }
580 else if ( mlt_properties_get_data( properties, "audio", NULL ) )
581 {
582 *buffer = mlt_properties_get_data( properties, "audio", NULL );
583 *format = mlt_properties_get_int( properties, "audio_format" );
584 *frequency = mlt_properties_get_int( properties, "audio_frequency" );
585 *channels = mlt_properties_get_int( properties, "audio_channels" );
586 *samples = mlt_properties_get_int( properties, "audio_samples" );
587 if ( self->convert_audio && *buffer && requested_format != mlt_audio_none )
588 self->convert_audio( self, buffer, format, requested_format );
589 }
590 else
591 {
592 int size = 0;
593 *samples = *samples <= 0 ? 1920 : *samples;
594 *channels = *channels <= 0 ? 2 : *channels;
595 *frequency = *frequency <= 0 ? 48000 : *frequency;
596 mlt_properties_set_int( properties, "audio_frequency", *frequency );
597 mlt_properties_set_int( properties, "audio_channels", *channels );
598 mlt_properties_set_int( properties, "audio_samples", *samples );
599 mlt_properties_set_int( properties, "audio_format", *format );
600
601 size = mlt_audio_format_size( *format, *samples, *channels );
602 if ( size )
603 *buffer = mlt_pool_alloc( size );
604 else
605 *buffer = NULL;
606 if ( *buffer )
607 memset( *buffer, 0, size );
608 mlt_properties_set_data( properties, "audio", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL );
609 mlt_properties_set_int( properties, "test_audio", 1 );
610 }
611
612 // TODO: This does not belong here
613 if ( *format == mlt_audio_s16 && mlt_properties_get( properties, "meta.volume" ) && *buffer )
614 {
615 double value = mlt_properties_get_double( properties, "meta.volume" );
616
617 if ( value == 0.0 )
618 {
619 memset( *buffer, 0, *samples * *channels * 2 );
620 }
621 else if ( value != 1.0 )
622 {
623 int total = *samples * *channels;
624 int16_t *p = *buffer;
625 while ( total -- )
626 {
627 *p = *p * value;
628 p ++;
629 }
630 }
631
632 mlt_properties_set( properties, "meta.volume", NULL );
633 }
634
635 return 0;
636 }
637
638 /** Set the audio on a frame.
639 *
640 * \public \memberof mlt_frame_s
641 * \param self a frame
642 * \param buffer an buffer containing audio samples
643 * \param format the format of the audio in the \p buffer
644 * \param size the total size of the buffer (optional)
645 * \param destructor a function that releases or deallocates the \p buffer
646 * \return true if error
647 */
648
mlt_frame_set_audio(mlt_frame self,void * buffer,mlt_audio_format format,int size,mlt_destructor destructor)649 int mlt_frame_set_audio( mlt_frame self, void *buffer, mlt_audio_format format, int size, mlt_destructor destructor )
650 {
651 mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "audio_format", format );
652 return mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "audio", buffer, size, destructor, NULL );
653 }
654
655 /** Get audio on a frame as a waveform image.
656 *
657 * This generates an 8-bit grayscale image representation of the audio in a
658 * frame. Currently, this only really works for 2 channels.
659 * This allocates the bitmap using mlt_pool so you should release the return
660 * value with \p mlt_pool_release.
661 *
662 * \public \memberof mlt_frame_s
663 * \param self a frame
664 * \param w the width of the image
665 * \param h the height of the image to create
666 * \return a pointer to a new bitmap
667 */
668
mlt_frame_get_waveform(mlt_frame self,int w,int h)669 unsigned char *mlt_frame_get_waveform( mlt_frame self, int w, int h )
670 {
671 int16_t *pcm = NULL;
672 mlt_properties properties = MLT_FRAME_PROPERTIES( self );
673 mlt_audio_format format = mlt_audio_s16;
674 int frequency = 16000;
675 int channels = 2;
676 mlt_producer producer = mlt_frame_get_original_producer( self );
677 double fps = mlt_producer_get_fps( mlt_producer_cut_parent( producer ) );
678 int samples = mlt_audio_calculate_frame_samples( fps, frequency, mlt_frame_get_position( self ) );
679
680 // Increase audio resolution proportional to requested image size
681 while ( samples < w )
682 {
683 frequency += 16000;
684 samples = mlt_audio_calculate_frame_samples( fps, frequency, mlt_frame_get_position( self ) );
685 }
686
687 // Get the pcm data
688 mlt_frame_get_audio( self, (void**)&pcm, &format, &frequency, &channels, &samples );
689
690 // Make an 8-bit buffer large enough to hold rendering
691 int size = w * h;
692 if ( size <= 0 )
693 return NULL;
694 unsigned char *bitmap = ( unsigned char* )mlt_pool_alloc( size );
695 if ( bitmap != NULL )
696 memset( bitmap, 0, size );
697 else
698 return NULL;
699 mlt_properties_set_data( properties, "waveform", bitmap, size, ( mlt_destructor )mlt_pool_release, NULL );
700
701 // Render vertical lines
702 int16_t *ubound = pcm + samples * channels;
703 int skip = samples / w;
704 skip = !skip ? 1 : skip;
705 unsigned char gray = 0xFF / skip;
706 int i, j, k;
707
708 // Iterate sample stream and along x coordinate
709 for ( i = 0; pcm < ubound; i++ )
710 {
711 // pcm data has channels interleaved
712 for ( j = 0; j < channels; j++, pcm++ )
713 {
714 // Determine sample's magnitude from 2s complement;
715 int pcm_magnitude = *pcm < 0 ? ~(*pcm) + 1 : *pcm;
716 // The height of a line is the ratio of the magnitude multiplied by
717 // the vertical resolution of a single channel
718 int height = h * pcm_magnitude / channels / 2 / 32768;
719 // Determine the starting y coordinate - left top, right bottom
720 int displacement = h * (j * 2 + 1) / channels / 2 - ( *pcm < 0 ? 0 : height );
721 // Position buffer pointer using y coordinate, stride, and x coordinate
722 unsigned char *p = bitmap + i / skip + displacement * w;
723
724 // Draw vertical line
725 for ( k = 0; k < height + 1; k++ )
726 if ( *pcm < 0 )
727 p[ w * k ] = ( k == 0 ) ? 0xFF : p[ w * k ] + gray;
728 else
729 p[ w * k ] = ( k == height ) ? 0xFF : p[ w * k ] + gray;
730 }
731 }
732
733 return bitmap;
734 }
735
736 /** Get the end service that produced self frame.
737 *
738 * This fetches the first producer of the frame and not any producers that
739 * encapsulate it.
740 *
741 * \public \memberof mlt_frame_s
742 * \param self a frame
743 * \return a producer
744 */
745
mlt_frame_get_original_producer(mlt_frame self)746 mlt_producer mlt_frame_get_original_producer( mlt_frame self )
747 {
748 if ( self != NULL )
749 return mlt_properties_get_data( MLT_FRAME_PROPERTIES( self ), "_producer", NULL );
750 return NULL;
751 }
752
753 /** Destroy the frame.
754 *
755 * \public \memberof mlt_frame_s
756 * \param self a frame
757 */
758
mlt_frame_close(mlt_frame self)759 void mlt_frame_close( mlt_frame self )
760 {
761 if ( self != NULL && mlt_properties_dec_ref( MLT_FRAME_PROPERTIES( self ) ) <= 0 )
762 {
763 mlt_deque_close( self->stack_image );
764 mlt_deque_close( self->stack_audio );
765 while( mlt_deque_peek_back( self->stack_service ) )
766 mlt_service_close( mlt_deque_pop_back( self->stack_service ) );
767 mlt_deque_close( self->stack_service );
768 mlt_properties_close( &self->parent );
769 free( self );
770 }
771 }
772
773 /***** convenience functions *****/
774
mlt_frame_write_ppm(mlt_frame frame)775 void mlt_frame_write_ppm( mlt_frame frame )
776 {
777 int width = 0;
778 int height = 0;
779 mlt_image_format format = mlt_image_rgb;
780 uint8_t *image;
781
782 if ( mlt_frame_get_image( frame, &image, &format, &width, &height, 0 ) == 0 )
783 {
784 FILE *file;
785 char filename[16];
786
787 sprintf( filename, "frame-%05d.ppm", (int)mlt_frame_get_position( frame ) );
788 file = mlt_fopen( filename, "wb" );
789 if ( !file )
790 return;
791 fprintf( file, "P6\n%d %d\n255\n", width, height);
792 fwrite( image, width * height * 3, 1, file );
793 fclose( file );
794 }
795 }
796
797 /** Get or create a properties object unique to this service instance.
798 *
799 * Use this function to hold a service's processing parameters for this
800 * particular frame. Set the parameters in the service's process function.
801 * Then, get the parameters in the function it pushes to the frame's audio
802 * or image stack. This makes the service more parallel by reducing race
803 * conditions and less sensitive to multiple instances (by not setting a
804 * non-unique property on the frame). Creation and destruction of the
805 * properties object is handled automatically.
806 *
807 * \public \memberof mlt_frame_s
808 * \param self a frame
809 * \param service a service
810 * \return a properties object
811 */
812
mlt_frame_unique_properties(mlt_frame self,mlt_service service)813 mlt_properties mlt_frame_unique_properties( mlt_frame self, mlt_service service )
814 {
815 mlt_properties frame_props = MLT_FRAME_PROPERTIES( self );
816 mlt_properties service_props = MLT_SERVICE_PROPERTIES( service );
817 char *unique = mlt_properties_get( service_props, "_unique_id" );
818 mlt_properties instance_props = mlt_properties_get_data( frame_props, unique, NULL );
819
820 if ( !instance_props )
821 {
822 instance_props = mlt_properties_new();
823 mlt_properties_set_data( frame_props, unique, instance_props, 0, (mlt_destructor) mlt_properties_close, NULL );
824 mlt_properties_set_lcnumeric( instance_props, mlt_properties_get_lcnumeric( service_props ) );
825 mlt_properties_set_data( instance_props, "_profile", mlt_service_profile( service ), 0, NULL, NULL );
826 }
827
828 return instance_props;
829 }
830
831 /** Get a properties object unique to this service instance.
832 *
833 * Unlike \p mlt_frame_unique_properties, this function does not create the
834 * service-unique properties object if it does not exist.
835 *
836 * \public \memberof mlt_frame_s
837 * \param self a frame
838 * \param service a service
839 * \return a properties object or NULL if it does not exist
840 */
841
mlt_frame_get_unique_properties(mlt_frame self,mlt_service service)842 mlt_properties mlt_frame_get_unique_properties( mlt_frame self, mlt_service service )
843 {
844 char *unique = mlt_properties_get( MLT_SERVICE_PROPERTIES(service), "_unique_id" );
845 return mlt_properties_get_data( MLT_FRAME_PROPERTIES(self), unique, NULL );
846 }
847
848 /** Make a copy of a frame.
849 *
850 * This does not copy the get_image/get_audio processing stacks or any
851 * data properties other than the audio and image.
852 *
853 * \public \memberof mlt_frame_s
854 * \param self the frame to clone
855 * \param is_deep a boolean to indicate whether to make a deep copy of the audio
856 * and video data chunks or to make a shallow copy by pointing to the supplied frame
857 * \return a almost-complete copy of the frame
858 * \todo copy the processing deques
859 */
860
mlt_frame_clone(mlt_frame self,int is_deep)861 mlt_frame mlt_frame_clone( mlt_frame self, int is_deep )
862 {
863 mlt_frame new_frame = mlt_frame_init( NULL );
864 mlt_properties properties = MLT_FRAME_PROPERTIES( self );
865 mlt_properties new_props = MLT_FRAME_PROPERTIES( new_frame );
866 void *data, *copy;
867 int size;
868
869 mlt_properties_inherit( new_props, properties );
870
871 // Carry over some special data properties for the multi consumer.
872 mlt_properties_set_data( new_props, "_producer",
873 mlt_frame_get_original_producer( self ), 0, NULL, NULL );
874 mlt_properties_set_data( new_props, "movit.convert",
875 mlt_properties_get_data( properties, "movit.convert", NULL), 0, NULL, NULL );
876
877 if ( is_deep )
878 {
879 data = mlt_properties_get_data( properties, "audio", &size );
880 if ( data )
881 {
882 if ( !size )
883 size = mlt_audio_format_size( mlt_properties_get_int( properties, "audio_format" ),
884 mlt_properties_get_int( properties, "audio_samples" ),
885 mlt_properties_get_int( properties, "audio_channels" ) );
886 copy = mlt_pool_alloc( size );
887 memcpy( copy, data, size );
888 mlt_properties_set_data( new_props, "audio", copy, size, mlt_pool_release, NULL );
889 }
890 data = mlt_properties_get_data( properties, "image", &size );
891 if ( data )
892 {
893 int width = mlt_properties_get_int( properties, "width" );
894 int height = mlt_properties_get_int( properties, "height" );
895
896 if ( ! size )
897 size = mlt_image_format_size( mlt_properties_get_int( properties, "format" ),
898 width, height, NULL );
899 copy = mlt_pool_alloc( size );
900 memcpy( copy, data, size );
901 mlt_properties_set_data( new_props, "image", copy, size, mlt_pool_release, NULL );
902
903 data = mlt_properties_get_data( properties, "alpha", &size );
904 if ( data )
905 {
906 if ( ! size )
907 size = width * height;
908 copy = mlt_pool_alloc( size );
909 memcpy( copy, data, size );
910 mlt_properties_set_data( new_props, "alpha", copy, size, mlt_pool_release, NULL );
911 };
912 }
913 }
914 else
915 {
916 // This frame takes a reference on the original frame since the data is a shallow copy.
917 mlt_properties_inc_ref( properties );
918 mlt_properties_set_data( new_props, "_cloned_frame", self, 0,
919 (mlt_destructor) mlt_frame_close, NULL );
920
921 // Copy properties
922 data = mlt_properties_get_data( properties, "audio", &size );
923 mlt_properties_set_data( new_props, "audio", data, size, NULL, NULL );
924 data = mlt_properties_get_data( properties, "image", &size );
925 mlt_properties_set_data( new_props, "image", data, size, NULL, NULL );
926 data = mlt_properties_get_data( properties, "alpha", &size );
927 mlt_properties_set_data( new_props, "alpha", data, size, NULL, NULL );
928 }
929
930 return new_frame;
931 }
932