#include <framework/mlt_filter.h>
#include <framework/mlt_frame.h>
+#include <framework/mlt_log.h>
#include <stdio.h>
#include <stdlib.h>
#include <samplerate.h>
+#include <string.h>
-#define BUFFER_LEN 20480
+// BUFFER_LEN is based on a maximum of 96KHz, 5 fps, 8 channels
+// TODO: dynamically allocate larger buffer size
+#define BUFFER_LEN ((96000/5) * 8 * sizeof(float))
#define RESAMPLE_TYPE SRC_SINC_FASTEST
/** Get the audio.
*/
-static int resample_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
+static int resample_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
{
- // Get the properties of the frame
- mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
-
// Get the filter service
mlt_filter filter = mlt_frame_pop_audio( frame );
// Get the resample information
int output_rate = mlt_properties_get_int( filter_properties, "frequency" );
- SRC_STATE *state = mlt_properties_get_data( filter_properties, "state", NULL );
- float *input_buffer = mlt_properties_get_data( filter_properties, "input_buffer", NULL );
- float *output_buffer = mlt_properties_get_data( filter_properties, "output_buffer", NULL );
- int channels_avail = *channels;
- SRC_DATA data;
- int i;
// If no resample frequency is specified, default to requested value
if ( output_rate == 0 )
output_rate = *frequency;
// Get the producer's audio
- mlt_frame_get_audio( frame, buffer, format, frequency, &channels_avail, samples );
-
- // Duplicate channels as necessary
- if ( channels_avail < *channels )
- {
- int size = *channels * *samples * sizeof( int16_t );
- int16_t *new_buffer = mlt_pool_alloc( size );
- int j, k = 0;
-
- // Duplicate the existing channels
- for ( i = 0; i < *samples; i++ )
- {
- for ( j = 0; j < *channels; j++ )
- {
- new_buffer[ ( i * *channels ) + j ] = (*buffer)[ ( i * channels_avail ) + k ];
- k = ( k + 1 ) % channels_avail;
- }
- }
-
- // Update the audio buffer now - destroys the old
- mlt_properties_set_data( properties, "audio", new_buffer, size, ( mlt_destructor )mlt_pool_release, NULL );
-
- *buffer = new_buffer;
- }
- else if ( channels_avail == 6 && *channels == 2 )
- {
- // Nasty hack for ac3 5.1 audio - may be a cause of failure?
- int size = *channels * *samples * sizeof( int16_t );
- int16_t *new_buffer = mlt_pool_alloc( size );
-
- // Drop all but the first *channels
- for ( i = 0; i < *samples; i++ )
- {
- new_buffer[ ( i * *channels ) + 0 ] = (*buffer)[ ( i * channels_avail ) + 2 ];
- new_buffer[ ( i * *channels ) + 1 ] = (*buffer)[ ( i * channels_avail ) + 3 ];
- }
-
- // Update the audio buffer now - destroys the old
- mlt_properties_set_data( properties, "audio", new_buffer, size, ( mlt_destructor )mlt_pool_release, NULL );
-
- *buffer = new_buffer;
- }
+ int error = mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples );
+ if ( error ) return error;
// Return now if no work to do
- if ( output_rate != *frequency )
+ if ( output_rate != *frequency && *frequency > 0 && *channels > 0 )
{
- float *p = input_buffer;
- float *end = p + *samples * *channels;
- int16_t *q = *buffer;
+ mlt_log_debug( MLT_FILTER_SERVICE(filter), "channels %d samples %d frequency %d -> %d\n",
+ *channels, *samples, *frequency, output_rate );
+
+ // Do not convert to float unless we need to change the rate
+ if ( *format != mlt_audio_f32le )
+ frame->convert_audio( frame, buffer, format, mlt_audio_f32le );
- // Convert to floating point
- while( p != end )
- *p ++ = ( float )( *q ++ ) / 32768.0;
+ mlt_service_lock( MLT_FILTER_SERVICE(filter) );
- // Resample
- data.data_in = input_buffer;
- data.data_out = output_buffer;
+ SRC_DATA data;
+ data.data_in = *buffer;
+ data.data_out = mlt_properties_get_data( filter_properties, "output_buffer", NULL );
data.src_ratio = ( float ) output_rate / ( float ) *frequency;
data.input_frames = *samples;
data.output_frames = BUFFER_LEN / *channels;
data.end_of_input = 0;
- i = src_process( state, &data );
- if ( i == 0 )
+
+ SRC_STATE *state = mlt_properties_get_data( filter_properties, "state", NULL );
+ if ( !state || mlt_properties_get_int( filter_properties, "channels" ) != *channels )
{
- if ( data.output_frames_gen > *samples )
- {
- *buffer = mlt_pool_realloc( *buffer, data.output_frames_gen * *channels * sizeof( int16_t ) );
- mlt_properties_set_data( properties, "audio", *buffer, *channels * data.output_frames_gen * 2, mlt_pool_release, NULL );
- }
+ // Recreate the resampler if the number of channels changed
+ state = src_new( RESAMPLE_TYPE, *channels, &error );
+ mlt_properties_set_data( filter_properties, "state", state, 0, (mlt_destructor) src_delete, NULL );
+ mlt_properties_set_int( filter_properties, "channels", *channels );
+ }
+ // Resample the audio
+ error = src_process( state, &data );
+ if ( !error )
+ {
+ // Update output variables
*samples = data.output_frames_gen;
*frequency = output_rate;
-
- p = output_buffer;
- q = *buffer;
- end = p + *samples * *channels;
-
- // Convert from floating back to signed 16bit
- while( p != end )
- {
- if ( *p > 1.0 )
- *p = 1.0;
- if ( *p < -1.0 )
- *p = -1.0;
- if ( *p > 0 )
- *q ++ = 32767 * *p ++;
- else
- *q ++ = 32768 * *p ++;
- }
+ *buffer = data.data_out;
}
else
- fprintf( stderr, "resample_get_audio: %s %d,%d,%d\n", src_strerror( i ), *frequency, *samples, output_rate );
+ {
+ mlt_log_error( MLT_FILTER_SERVICE( filter ), "%s %d,%d,%d\n", src_strerror( error ), *frequency, *samples, output_rate );
+ }
+ mlt_service_unlock( MLT_FILTER_SERVICE(filter) );
}
- return 0;
+ return error;
}
/** Filter processing.
SRC_STATE *state = src_new( RESAMPLE_TYPE, 2 /* channels */, &error );
if ( error == 0 )
{
- void *input_buffer = mlt_pool_alloc( BUFFER_LEN );
void *output_buffer = mlt_pool_alloc( BUFFER_LEN );
this->process = filter_process;
if ( arg != NULL )
mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "frequency", atoi( arg ) );
mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "channels", 2 );
mlt_properties_set_data( MLT_FILTER_PROPERTIES( this ), "state", state, 0, (mlt_destructor)src_delete, NULL );
- mlt_properties_set_data( MLT_FILTER_PROPERTIES( this ), "input_buffer", input_buffer, BUFFER_LEN, mlt_pool_release, NULL );
mlt_properties_set_data( MLT_FILTER_PROPERTIES( this ), "output_buffer", output_buffer, BUFFER_LEN, mlt_pool_release, NULL );
}
else