2 * producer_blipflash.c -- blip/flash generating producer
3 * Copyright (C) 2013 Brian Matherly
4 * Author: Brian Matherly <pez4brian@yahoo.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <framework/mlt.h>
27 /** Fill an audio buffer with 1kHz "blip" samples.
30 static void fill_blip( mlt_properties producer_properties, float* buffer, int frequency, int channels, int samples )
32 int new_size = samples * channels * sizeof( float );
34 float* blip = mlt_properties_get_data( producer_properties, "_blip", &old_size );
36 if( !blip || new_size > old_size )
38 blip = mlt_pool_alloc( new_size );
40 // Fill the blip buffer
46 for( s = 0; s < samples; s++ )
49 float t = (float)s/(float)frequency;
50 // Add 90 deg so the blip always starts at 1 for easy detection.
51 float phase = M_PI / 2;
52 float value = sin( 2*M_PI*f*t + phase );
54 for( c = 0; c < channels; c++ )
56 float* sample_ptr = ((float*) blip) + (c * samples) + s;
61 // Cache the audio blip to save from regenerating it with every blip.
62 mlt_properties_set_data( producer_properties, "_blip", blip, new_size, mlt_pool_release, NULL );
65 if( blip ) memcpy( buffer, blip, new_size );
68 static int producer_get_audio( mlt_frame frame, int16_t** buffer, mlt_audio_format* format, int* frequency, int* channels, int* samples )
70 mlt_producer producer = mlt_properties_get_data( MLT_FRAME_PROPERTIES( frame ), "_producer_blipflash", NULL );
71 mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer );
72 int size = *samples * *channels * sizeof( float );
73 double fps = mlt_producer_get_fps( producer );
74 int frames = mlt_frame_get_position( frame ) + mlt_properties_get_int( producer_properties, "offset" );
75 int seconds = frames / fps;
77 // Correct the returns if necessary
78 *format = mlt_audio_float;
79 *frequency = *frequency <= 0 ? 48000 : *frequency;
80 *channels = *channels <= 0 ? 2 : *channels;
81 *samples = *samples <= 0 ? mlt_sample_calculator( fps, *frequency, frames ) : *samples;
83 // Allocate the buffer
84 *buffer = mlt_pool_alloc( size );
86 // Determine if this should be a blip or silence.
87 frames = frames % lrint( fps );
88 seconds = seconds % mlt_properties_get_int( producer_properties, "period" );
89 if( seconds == 0 && frames == 0 )
91 fill_blip( producer_properties, (float*)*buffer, *frequency, *channels, *samples );
96 memset( *buffer, 0, size );
99 // Set the buffer for destruction
100 mlt_frame_set_audio( frame, *buffer, *format, size, mlt_pool_release );
105 /** Fill an image buffer with either white (flash) or black as requested.
108 static void fill_image( mlt_properties producer_properties, char* color, uint8_t* buffer, mlt_image_format format, int width, int height )
111 int new_size = mlt_image_format_size( format, width, height, NULL );
113 uint8_t* image = image = mlt_properties_get_data( producer_properties, color, &old_size );
115 if( !image || new_size > old_size )
117 // Need to create a new cached image.
118 image = mlt_pool_alloc( new_size );
125 if( !strcmp( color, "_flash" ) )
127 r = g = b = 255; // White
131 r = g = b = 0; // Black
137 case mlt_image_yuv422:
139 int uneven = width % 2;
140 int count = ( width - uneven ) / 2 + 1;
143 RGB2YUV_601_SCALED( r, g, b, y, u, v );
163 case mlt_image_rgb24:
165 int i = width * height + 1;
174 case mlt_image_rgb24a:
176 int i = width * height + 1;
182 *p ++ = 255; // alpha
187 // Cache the image to save from regenerating it with every frame.
188 mlt_properties_set_data( producer_properties, color, image, new_size, mlt_pool_release, NULL );
192 if( image ) memcpy( buffer, image, new_size );
195 static int producer_get_image( mlt_frame frame, uint8_t** buffer, mlt_image_format* format, int* width, int* height, int writable )
197 mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
198 mlt_producer producer = mlt_properties_get_data( MLT_FRAME_PROPERTIES( frame ), "_producer_blipflash", NULL );
199 mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer );
201 double fps = mlt_producer_get_fps( producer );
202 int frames = mlt_frame_get_position( frame );
203 int seconds = frames / fps;
205 mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) );
207 // Correct the returns if necessary
208 if( *format != mlt_image_yuv422 && *format != mlt_image_rgb24 && *format != mlt_image_rgb24a )
209 *format = mlt_image_yuv422;
211 *width = mlt_service_profile( MLT_PRODUCER_SERVICE(producer) )->width;
213 *height = mlt_service_profile( MLT_PRODUCER_SERVICE(producer) )->height;
215 // Allocate the buffer
216 size = mlt_image_format_size( *format, *width, *height, NULL );
217 *buffer = mlt_pool_alloc( size );
219 // Determine if this should be a flash or black.
220 frames = frames % lrint( fps );
221 seconds = seconds % mlt_properties_get_int( producer_properties, "period" );
222 if( seconds == 0 && frames == 0 )
224 fill_image( producer_properties, "_flash", *buffer, *format, *width, *height );
228 fill_image( producer_properties, "_black", *buffer, *format, *width, *height );
231 mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) );
233 // Create the alpha channel
234 int alpha_size = *width * *height;
235 uint8_t *alpha = mlt_pool_alloc( alpha_size );
237 memset( alpha, 255, alpha_size );
240 mlt_frame_set_image( frame, *buffer, size, mlt_pool_release );
241 mlt_frame_set_alpha( frame, alpha, alpha_size, mlt_pool_release );
242 mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( producer_properties, "aspect_ratio" ) );
243 mlt_properties_set_int( properties, "progressive", 1 );
244 mlt_properties_set_int( properties, "meta.media.width", *width );
245 mlt_properties_set_int( properties, "meta.media.height", *height );
250 static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
253 *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) );
255 if ( *frame != NULL )
257 // Obtain properties of frame
258 mlt_properties frame_properties = MLT_FRAME_PROPERTIES( *frame );
260 // Save the producer to be used later
261 mlt_properties_set_data( frame_properties, "_producer_blipflash", producer, 0, NULL, NULL );
263 // Update time code on the frame
264 mlt_frame_set_position( *frame, mlt_producer_position( producer ) );
266 // Configure callbacks
267 mlt_frame_push_get_image( *frame, producer_get_image );
268 mlt_frame_push_audio( *frame, producer_get_audio );
271 // Calculate the next time code
272 mlt_producer_prepare_next( producer );
277 static void producer_close( mlt_producer this )
280 mlt_producer_close( this );
287 mlt_producer producer_blipflash_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
289 // Create a new producer object
290 mlt_producer producer = mlt_producer_new( profile );
291 mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer );
293 // Initialize the producer
296 mlt_properties_set_int( producer_properties, "period", 1 );
297 mlt_properties_set_int( producer_properties, "offset", 0 );
299 // Callback registration
300 producer->get_frame = producer_get_frame;
301 producer->close = ( mlt_destructor )producer_close;