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