From: Dan Dennedy Date: Tue, 4 Aug 2009 04:36:59 +0000 (-0700) Subject: Refactor audio conversion and mixing. X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=3225ba127131f97c1e0bd6d3bbc144fd50c00c84;p=mlt Refactor audio conversion and mixing. Signed-off-by: Dan Dennedy --- diff --git a/src/framework/Makefile b/src/framework/Makefile index 85f554dd..b523e36e 100644 --- a/src/framework/Makefile +++ b/src/framework/Makefile @@ -69,7 +69,7 @@ SRCS := $(OBJS:.o=.c) CFLAGS += $(RDYNAMIC) -DPREFIX="\"$(prefix)\"" -DLIBDIR="\"$(libdir)\"" -LDFLAGS += -lm $(LIBDL) -lpthread +LDFLAGS += $(LIBDL) -lpthread all: $(TARGET) diff --git a/src/framework/mlt_consumer.c b/src/framework/mlt_consumer.c index 93afe447..37e7d3fa 100644 --- a/src/framework/mlt_consumer.c +++ b/src/framework/mlt_consumer.c @@ -579,13 +579,13 @@ static void *consumer_read_ahead_thread( void *arg ) int preview_format = mlt_properties_get_int( properties, "preview_format" ); // Get the audio settings - mlt_audio_format afmt = mlt_audio_pcm; + mlt_audio_format afmt = mlt_audio_s16; int counter = 0; double fps = mlt_properties_get_double( properties, "fps" ); int channels = mlt_properties_get_int( properties, "channels" ); int frequency = mlt_properties_get_int( properties, "frequency" ); int samples = 0; - int16_t *pcm = NULL; + void *audio = NULL; // See if audio is turned off int audio_off = mlt_properties_get_int( properties, "audio_off" ); @@ -631,7 +631,7 @@ static void *consumer_read_ahead_thread( void *arg ) if ( !audio_off ) { samples = mlt_sample_calculator( fps, frequency, counter++ ); - mlt_frame_get_audio( frame, &pcm, &afmt, &frequency, &channels, &samples ); + mlt_frame_get_audio( frame, &audio, &afmt, &frequency, &channels, &samples ); } // Unlock the lock object @@ -723,7 +723,7 @@ static void *consumer_read_ahead_thread( void *arg ) if ( !audio_off ) { samples = mlt_sample_calculator( fps, frequency, counter++ ); - mlt_frame_get_audio( frame, &pcm, &afmt, &frequency, &channels, &samples ); + mlt_frame_get_audio( frame, &audio, &afmt, &frequency, &channels, &samples ); } // Increment the time take for this frame diff --git a/src/framework/mlt_frame.c b/src/framework/mlt_frame.c index 6bd5442c..804f9b5d 100644 --- a/src/framework/mlt_frame.c +++ b/src/framework/mlt_frame.c @@ -30,7 +30,6 @@ #include #include #include -#include /** Constructor for a frame. */ @@ -400,24 +399,46 @@ uint8_t *mlt_frame_get_alpha_mask( mlt_frame this ) return alpha; } -int mlt_frame_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) +const char * mlt_audio_format_name( mlt_audio_format format ) +{ + switch ( format ) + { + case mlt_audio_none: return "none"; + case mlt_audio_s16: return "s16"; + case mlt_audio_s32: return "s32"; + case mlt_audio_float: return "float"; + } + return "invalid"; +} + +int mlt_frame_get_audio( mlt_frame this, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { mlt_get_audio get_audio = mlt_frame_pop_audio( this ); mlt_properties properties = MLT_FRAME_PROPERTIES( this ); int hide = mlt_properties_get_int( properties, "test_audio" ); + mlt_audio_format requested_format = *format; if ( hide == 0 && get_audio != NULL ) { mlt_position position = mlt_frame_get_position( this ); get_audio( this, buffer, format, frequency, channels, samples ); mlt_frame_set_position( this, position ); + mlt_properties_set_int( properties, "audio_frequency", *frequency ); + mlt_properties_set_int( properties, "audio_channels", *channels ); + mlt_properties_set_int( properties, "audio_samples", *samples ); + mlt_properties_set_int( properties, "audio_format", *format ); + if ( this->convert_audio ) + this->convert_audio( this, buffer, format, requested_format ); } else if ( mlt_properties_get_data( properties, "audio", NULL ) ) { *buffer = mlt_properties_get_data( properties, "audio", NULL ); + *format = mlt_properties_get_int( properties, "audio_format" ); *frequency = mlt_properties_get_int( properties, "audio_frequency" ); *channels = mlt_properties_get_int( properties, "audio_channels" ); *samples = mlt_properties_get_int( properties, "audio_samples" ); + if ( this->convert_audio ) + this->convert_audio( this, buffer, format, requested_format ); } else { @@ -425,19 +446,37 @@ int mlt_frame_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *for *samples = *samples <= 0 ? 1920 : *samples; *channels = *channels <= 0 ? 2 : *channels; *frequency = *frequency <= 0 ? 48000 : *frequency; - size = *samples * *channels * sizeof( int16_t ); - *buffer = mlt_pool_alloc( size ); - if ( *buffer != NULL ) + mlt_properties_set_int( properties, "audio_frequency", *frequency ); + mlt_properties_set_int( properties, "audio_channels", *channels ); + mlt_properties_set_int( properties, "audio_samples", *samples ); + mlt_properties_set_int( properties, "audio_format", *format ); + + switch( *format ) + { + case mlt_image_none: + size = 0; + *buffer = NULL; + break; + case mlt_audio_s16: + size = *samples * *channels * sizeof( int16_t ); + break; + case mlt_audio_s32: + size = *samples * *channels * sizeof( int32_t ); + break; + case mlt_audio_float: + size = *samples * *channels * sizeof( float ); + break; + } + if ( size ) + *buffer = mlt_pool_alloc( size ); + if ( *buffer ) memset( *buffer, 0, size ); mlt_properties_set_data( properties, "audio", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL ); mlt_properties_set_int( properties, "test_audio", 1 ); } - mlt_properties_set_int( properties, "audio_frequency", *frequency ); - mlt_properties_set_int( properties, "audio_channels", *channels ); - mlt_properties_set_int( properties, "audio_samples", *samples ); - - if ( mlt_properties_get( properties, "meta.volume" ) ) + // TODO: This does not belong here + if ( *format == mlt_audio_s16 && mlt_properties_get( properties, "meta.volume" ) ) { double value = mlt_properties_get_double( properties, "meta.volume" ); @@ -462,18 +501,24 @@ int mlt_frame_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *for return 0; } +int mlt_frame_set_audio( mlt_frame this, void *buffer, mlt_audio_format format, int size, mlt_destructor destructor ) +{ + mlt_properties_set_int( MLT_FRAME_PROPERTIES( this ), "audio_format", format ); + return mlt_properties_set_data( MLT_FRAME_PROPERTIES( this ), "audio", buffer, size, destructor, NULL ); +} + unsigned char *mlt_frame_get_waveform( mlt_frame this, int w, int h ) { int16_t *pcm = NULL; mlt_properties properties = MLT_FRAME_PROPERTIES( this ); - mlt_audio_format format = mlt_audio_pcm; + mlt_audio_format format = mlt_audio_s16; int frequency = 32000; // lower frequency available? int channels = 2; double fps = mlt_profile_fps( NULL ); int samples = mlt_sample_calculator( fps, frequency, mlt_frame_get_position( this ) ); // Get the pcm data - mlt_frame_get_audio( this, &pcm, &format, &frequency, &channels, &samples ); + mlt_frame_get_audio( this, (void**)&pcm, &format, &frequency, &channels, &samples ); // Make an 8-bit buffer large enough to hold rendering int size = w * h; @@ -539,139 +584,6 @@ void mlt_frame_close( mlt_frame this ) /***** convenience functions *****/ -int mlt_frame_mix_audio( mlt_frame this, mlt_frame that, float weight_start, float weight_end, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) -{ - int ret = 0; - int16_t *src, *dest; - int frequency_src = *frequency, frequency_dest = *frequency; - int channels_src = *channels, channels_dest = *channels; - int samples_src = *samples, samples_dest = *samples; - int i, j; - double d = 0, s = 0; - - mlt_frame_get_audio( that, &src, format, &frequency_src, &channels_src, &samples_src ); - mlt_frame_get_audio( this, &dest, format, &frequency_dest, &channels_dest, &samples_dest ); - - int silent = mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "silent_audio" ); - mlt_properties_set_int( MLT_FRAME_PROPERTIES( this ), "silent_audio", 0 ); - if ( silent ) - memset( dest, 0, samples_dest * channels_dest * sizeof( int16_t ) ); - - silent = mlt_properties_get_int( MLT_FRAME_PROPERTIES( that ), "silent_audio" ); - mlt_properties_set_int( MLT_FRAME_PROPERTIES( that ), "silent_audio", 0 ); - if ( silent ) - memset( src, 0, samples_src * channels_src * sizeof( int16_t ) ); - - if ( channels_src > 6 ) - channels_src = 0; - if ( channels_dest > 6 ) - channels_dest = 0; - if ( samples_src > 4000 ) - samples_src = 0; - if ( samples_dest > 4000 ) - samples_dest = 0; - - // determine number of samples to process - *samples = samples_src < samples_dest ? samples_src : samples_dest; - *channels = channels_src < channels_dest ? channels_src : channels_dest; - *buffer = dest; - *frequency = frequency_dest; - - // Compute a smooth ramp over start to end - float weight = weight_start; - float weight_step = ( weight_end - weight_start ) / *samples; - - if ( src == dest ) - { - *samples = samples_src; - *channels = channels_src; - *buffer = src; - *frequency = frequency_src; - return ret; - } - - // Mixdown - for ( i = 0; i < *samples; i++ ) - { - for ( j = 0; j < *channels; j++ ) - { - if ( j < channels_dest ) - d = (double) dest[ i * channels_dest + j ]; - if ( j < channels_src ) - s = (double) src[ i * channels_src + j ]; - dest[ i * channels_dest + j ] = s * weight + d * ( 1.0 - weight ); - } - weight += weight_step; - } - - return ret; -} - -// Replacement for broken mlt_frame_audio_mix - this filter uses an inline low pass filter -// to allow mixing without volume hacking -int mlt_frame_combine_audio( mlt_frame this, mlt_frame that, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) -{ - int ret = 0; - int16_t *src, *dest; - int frequency_src = *frequency, frequency_dest = *frequency; - int channels_src = *channels, channels_dest = *channels; - int samples_src = *samples, samples_dest = *samples; - int i, j; - double vp[ 6 ]; - double b_weight = 1.0; - - if ( mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "meta.mixdown" ) ) - b_weight = 1.0 - mlt_properties_get_double( MLT_FRAME_PROPERTIES( this ), "meta.volume" ); - - mlt_frame_get_audio( that, &src, format, &frequency_src, &channels_src, &samples_src ); - mlt_frame_get_audio( this, &dest, format, &frequency_dest, &channels_dest, &samples_dest ); - - int silent = mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "silent_audio" ); - mlt_properties_set_int( MLT_FRAME_PROPERTIES( this ), "silent_audio", 0 ); - if ( silent ) - memset( dest, 0, samples_dest * channels_dest * sizeof( int16_t ) ); - - silent = mlt_properties_get_int( MLT_FRAME_PROPERTIES( that ), "silent_audio" ); - mlt_properties_set_int( MLT_FRAME_PROPERTIES( that ), "silent_audio", 0 ); - if ( silent ) - memset( src, 0, samples_src * channels_src * sizeof( int16_t ) ); - - if ( src == dest ) - { - *samples = samples_src; - *channels = channels_src; - *buffer = src; - *frequency = frequency_src; - return ret; - } - - // determine number of samples to process - *samples = samples_src < samples_dest ? samples_src : samples_dest; - *channels = channels_src < channels_dest ? channels_src : channels_dest; - *buffer = dest; - *frequency = frequency_dest; - - for ( j = 0; j < *channels; j++ ) - vp[ j ] = ( double )dest[ j ]; - - double Fc = 0.5; - double B = exp(-2.0 * M_PI * Fc); - double A = 1.0 - B; - double v; - - for ( i = 0; i < *samples; i++ ) - { - for ( j = 0; j < *channels; j++ ) - { - v = ( double )( b_weight * dest[ i * channels_dest + j ] + src[ i * channels_src + j ] ); - v = v < -32767 ? -32767 : v > 32768 ? 32768 : v; - vp[ j ] = dest[ i * channels_dest + j ] = ( int16_t )( v * A + vp[ j ] * B ); - } - } - - return ret; -} - /* Will this break when mlt_position is converted to double? -Zach */ int mlt_sample_calculator( float fps, int frequency, int64_t position ) { diff --git a/src/framework/mlt_frame.h b/src/framework/mlt_frame.h index 91aa79f4..7def364d 100644 --- a/src/framework/mlt_frame.h +++ b/src/framework/mlt_frame.h @@ -38,7 +38,7 @@ typedef int ( *mlt_get_image )( mlt_frame self, uint8_t **buffer, mlt_image_form * */ -typedef int ( *mlt_get_audio )( mlt_frame self, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ); +typedef int ( *mlt_get_audio )( mlt_frame self, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ); /** \brief Frame class * @@ -60,6 +60,7 @@ struct mlt_frame_s /* Virtual methods */ uint8_t * ( *get_alpha_mask )( mlt_frame self ); int ( *convert_image )( mlt_frame self, uint8_t **image, mlt_image_format *input, mlt_image_format output ); + int ( *convert_audio )( mlt_frame self, void **audio, mlt_audio_format *input, mlt_audio_format output ); /* Private properties */ mlt_deque stack_image; @@ -83,7 +84,8 @@ extern int mlt_frame_set_position( mlt_frame self, mlt_position value ); extern void mlt_frame_replace_image( mlt_frame self, uint8_t *image, mlt_image_format format, int width, int height ); extern int mlt_frame_get_image( mlt_frame self, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ); extern uint8_t *mlt_frame_get_alpha_mask( mlt_frame self ); -extern int mlt_frame_get_audio( mlt_frame self, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ); +extern int mlt_frame_get_audio( mlt_frame self, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ); +extern int mlt_frame_set_audio( mlt_frame self, void *buffer, mlt_audio_format, int size, mlt_destructor ); extern unsigned char *mlt_frame_get_waveform( mlt_frame self, int w, int h ); extern int mlt_frame_push_get_image( mlt_frame self, mlt_get_image get_image ); extern mlt_get_image mlt_frame_pop_get_image( mlt_frame self ); @@ -100,11 +102,10 @@ extern mlt_producer mlt_frame_get_original_producer( mlt_frame self ); extern void mlt_frame_close( mlt_frame self ); /* convenience functions */ -extern int mlt_frame_mix_audio( mlt_frame self, mlt_frame that, float weight_start, float weight_end, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ); -extern int mlt_frame_combine_audio( mlt_frame self, mlt_frame that, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ); extern int mlt_sample_calculator( float fps, int frequency, int64_t position ); extern int64_t mlt_sample_calculator_to_now( float fps, int frequency, int64_t position ); extern const char * mlt_image_format_name( mlt_image_format format ); +extern const char * mlt_audio_format_name( mlt_audio_format format ); /** This macro scales rgb into the yuv gamut - y is scaled by 219/255 and uv by 224/255. */ #define RGB2YUV(r, g, b, y, u, v)\ diff --git a/src/framework/mlt_tractor.c b/src/framework/mlt_tractor.c index 40c78215..e3c79acf 100644 --- a/src/framework/mlt_tractor.c +++ b/src/framework/mlt_tractor.c @@ -284,7 +284,7 @@ static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_forma return 0; } -static int producer_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) +static int producer_get_audio( mlt_frame this, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { mlt_properties properties = MLT_FRAME_PROPERTIES( this ); mlt_frame frame = mlt_frame_pop_audio( this ); diff --git a/src/framework/mlt_types.h b/src/framework/mlt_types.h index 921dd479..05c7bf5c 100644 --- a/src/framework/mlt_types.h +++ b/src/framework/mlt_types.h @@ -49,7 +49,10 @@ mlt_image_format; typedef enum { mlt_audio_none = 0,/**< audio not available */ - mlt_audio_pcm /**< signed 16-bit interleaved PCM */ + mlt_audio_pcm = 1, /**< \deprecated signed 16-bit interleaved PCM */ + mlt_audio_s16 = 1, /**< signed 16-bit interleaved PCM */ + mlt_audio_s32, /**< signed 32-bit non-interleaved PCM */ + mlt_audio_float /**< 32-bit non-interleaved floating point */ } mlt_audio_format; diff --git a/src/mlt++/MltFrame.cpp b/src/mlt++/MltFrame.cpp index 8eee724b..e2b3aa2d 100644 --- a/src/mlt++/MltFrame.cpp +++ b/src/mlt++/MltFrame.cpp @@ -72,9 +72,9 @@ unsigned char *Frame::fetch_image( mlt_image_format f, int w, int h, int writabl return image; } -int16_t *Frame::get_audio( mlt_audio_format &format, int &frequency, int &channels, int &samples ) +void *Frame::get_audio( mlt_audio_format &format, int &frequency, int &channels, int &samples ) { - int16_t *audio = NULL; + void *audio = NULL; mlt_frame_get_audio( get_frame( ), &audio, &format, &frequency, &channels, &samples ); return audio; } diff --git a/src/mlt++/MltFrame.h b/src/mlt++/MltFrame.h index 212d0bad..4c2e3d76 100644 --- a/src/mlt++/MltFrame.h +++ b/src/mlt++/MltFrame.h @@ -43,7 +43,7 @@ namespace Mlt mlt_properties get_properties( ); uint8_t *get_image( mlt_image_format &format, int &w, int &h, int writable = 0 ); unsigned char *fetch_image( mlt_image_format format, int w, int h, int writable = 0 ); - int16_t *get_audio( mlt_audio_format &format, int &frequency, int &channels, int &samples ); + void *get_audio( mlt_audio_format &format, int &frequency, int &channels, int &samples ); unsigned char *get_waveform( int w, int h ); Producer *get_original_producer( ); }; diff --git a/src/mlt++/configure b/src/mlt++/configure index 1d46adbd..e83b6ed1 100755 --- a/src/mlt++/configure +++ b/src/mlt++/configure @@ -1,5 +1,5 @@ #!/bin/sh -echo "soversion=2" > config.mak +echo "soversion=3" > config.mak echo "mlt++ -I$prefix/include -I$prefix/include/mlt++ -D_REENTRANT -L$libdir -lmlt++" >> ../../packages.dat WARNINGS="-W -Wwrite-strings -Wcast-qual -Wpointer-arith -Wcast-align -Wredundant-decls" diff --git a/src/modules/avformat/consumer_avformat.c b/src/modules/avformat/consumer_avformat.c index 2229ff17..cf53e124 100644 --- a/src/modules/avformat/consumer_avformat.c +++ b/src/modules/avformat/consumer_avformat.c @@ -790,7 +790,7 @@ static void *consumer_thread( void *arg ) int img_height = height; // Get default audio properties - mlt_audio_format aud_fmt = mlt_audio_pcm; + mlt_audio_format aud_fmt = mlt_audio_s16; int channels = mlt_properties_get_int( properties, "channels" ); int frequency = mlt_properties_get_int( properties, "frequency" ); int16_t *pcm = NULL; @@ -1004,7 +1004,7 @@ static void *consumer_thread( void *arg ) if ( !terminated && audio_st ) { samples = mlt_sample_calculator( fps, frequency, count ++ ); - mlt_frame_get_audio( frame, &pcm, &aud_fmt, &frequency, &channels, &samples ); + mlt_frame_get_audio( frame, (void**) &pcm, &aud_fmt, &frequency, &channels, &samples ); // Create the fifo if we don't have one if ( fifo == NULL ) diff --git a/src/modules/avformat/filter_avresample.c b/src/modules/avformat/filter_avresample.c index ff8a1698..fd765b7e 100644 --- a/src/modules/avformat/filter_avresample.c +++ b/src/modules/avformat/filter_avresample.c @@ -31,7 +31,7 @@ /** 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 ); @@ -60,6 +60,7 @@ static int resample_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form output_rate = *frequency; // Get the producer's audio + *format = mlt_audio_s16; mlt_frame_get_audio( frame, buffer, format, frequency, &channels_avail, samples ); // Duplicate channels as necessary @@ -74,7 +75,7 @@ static int resample_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form { for ( j = 0; j < *channels; j++ ) { - new_buffer[ ( i * *channels ) + j ] = (*buffer)[ ( i * channels_avail ) + k ]; + new_buffer[ ( i * *channels ) + j ] = ((int16_t*)(*buffer))[ ( i * channels_avail ) + k ]; k = ( k + 1 ) % channels_avail; } } @@ -93,8 +94,8 @@ static int resample_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form // 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 ]; + new_buffer[ ( i * *channels ) + 0 ] = ((int16_t*)(*buffer))[ ( i * channels_avail ) + 2 ]; + new_buffer[ ( i * *channels ) + 1 ] = ((int16_t*)(*buffer))[ ( i * channels_avail ) + 3 ]; } // Update the audio buffer now - destroys the old @@ -129,16 +130,17 @@ static int resample_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form // Resample the audio used = audio_resample( resample, sample_buffer, *buffer, *samples ); + int size = used * *channels * sizeof( int16_t ); // Resize if necessary if ( used > *samples ) { - *buffer = mlt_pool_realloc( *buffer, *samples * *channels * sizeof( int16_t ) ); - mlt_properties_set_data( properties, "audio", *buffer, *channels * used * sizeof( int16_t ), mlt_pool_release, NULL ); + *buffer = mlt_pool_realloc( *buffer, size ); + mlt_frame_set_audio( frame, *buffer, *format, size, mlt_pool_release ); } // Copy samples - memcpy( *buffer, sample_buffer, *channels * used * sizeof( int16_t ) ); + memcpy( *buffer, sample_buffer, size ); // Update output variables *samples = used; diff --git a/src/modules/avformat/producer_avformat.c b/src/modules/avformat/producer_avformat.c index 5b2919dc..e99d6bdc 100644 --- a/src/modules/avformat/producer_avformat.c +++ b/src/modules/avformat/producer_avformat.c @@ -1104,7 +1104,7 @@ static void producer_set_up_video( mlt_producer this, mlt_frame frame ) /** Get the audio from a frame. */ -static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) +static int producer_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the properties from the frame mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); @@ -1318,8 +1318,10 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form av_free_packet( &pkt ); } - *buffer = mlt_pool_alloc( *samples * *channels * sizeof( int16_t ) ); - mlt_properties_set_data( frame_properties, "audio", *buffer, 0, ( mlt_destructor )mlt_pool_release, NULL ); + int size = *samples * *channels * sizeof( int16_t ); + *format = mlt_audio_s16; + *buffer = mlt_pool_alloc( size ); + mlt_frame_set_audio( frame, *buffer, *format, size, mlt_pool_release ); // Now handle the audio if we have enough if ( audio_used >= *samples ) diff --git a/src/modules/core/Makefile b/src/modules/core/Makefile index fbd83a59..7c371ad9 100644 --- a/src/modules/core/Makefile +++ b/src/modules/core/Makefile @@ -13,6 +13,7 @@ OBJS = factory.o \ producer_loader.o \ producer_noise.o \ producer_ppm.o \ + filter_audioconvert.o \ filter_brightness.o \ filter_channelcopy.o \ filter_crop.o \ diff --git a/src/modules/core/factory.c b/src/modules/core/factory.c index e6ae8896..b0aecb9e 100644 --- a/src/modules/core/factory.c +++ b/src/modules/core/factory.c @@ -22,6 +22,7 @@ #include extern mlt_consumer consumer_null_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); +extern mlt_filter filter_audioconvert_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_brightness_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_channelcopy_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_crop_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); @@ -53,6 +54,7 @@ extern mlt_transition transition_mix_init( mlt_profile profile, mlt_service_type MLT_REPOSITORY { MLT_REGISTER( consumer_type, "null", consumer_null_init ); + MLT_REGISTER( filter_type, "audioconvert", filter_audioconvert_init ); MLT_REGISTER( filter_type, "brightness", filter_brightness_init ); MLT_REGISTER( filter_type, "channelcopy", filter_channelcopy_init ); MLT_REGISTER( filter_type, "crop", filter_crop_init ); diff --git a/src/modules/core/filter_audioconvert.c b/src/modules/core/filter_audioconvert.c new file mode 100644 index 00000000..0794281c --- /dev/null +++ b/src/modules/core/filter_audioconvert.c @@ -0,0 +1,190 @@ +/* + * filter_audioconvert.c -- convert from one audio format to another + * Copyright (C) 2009 Ushodaya Enterprises Limited + * Author: Dan Dennedy + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +#include +#include + +static int convert_audio( mlt_frame frame, void **audio, mlt_audio_format *format, mlt_audio_format requested_format ) +{ + int error = 0; + mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); + int channels = mlt_properties_get_int( properties, "audio_channels" ); + int samples = mlt_properties_get_int( properties, "audio_samples" ); + int size = 0; + + if ( *format != requested_format ) + { + mlt_log_debug( NULL, "[filter audioconvert] %s -> %s %d channels %d samples\n", + mlt_audio_format_name( *format ), mlt_audio_format_name( requested_format ), + channels, samples ); + switch ( *format ) + { + case mlt_audio_s16: + switch ( requested_format ) + { + case mlt_audio_s32: + { + size = channels * samples * sizeof(int32_t); + int32_t *buffer = mlt_pool_alloc( size ); + int32_t *p = buffer; + int c; + for ( c = 0; c < channels; c++ ) + { + int16_t *q = (int16_t*) *audio + c; + int i = samples + 1; + while ( --i ) + { + *p++ = (int32_t) *q << 16; + q += channels; + } + } + *audio = buffer; + break; + } + case mlt_audio_float: + { + size = channels * samples * sizeof(float); + float *buffer = mlt_pool_alloc( size ); + float *p = buffer; + int c; + for ( c = 0; c < channels; c++ ) + { + int16_t *q = (int16_t*) *audio + c; + int i = samples + 1; + while ( --i ) + { + *p++ = (float)( *q ) / 32768.0; + q += channels; + } + } + *audio = buffer; + break; + } + default: + error = 1; + } + break; + case mlt_audio_s32: + switch ( requested_format ) + { + case mlt_audio_s16: + { + size = channels * samples * sizeof(int16_t); + int16_t *buffer = mlt_pool_alloc( size ); + int16_t *p = buffer; + int32_t *q = (int32_t*) *audio; + int s, c; + for ( s = 0; s < samples; s++ ) + for ( c = 0; c < channels; c++ ) + *p++ = *( q + c * samples + s ) >> 16; + *audio = buffer; + break; + } + case mlt_audio_float: + { + size = channels * samples * sizeof(float); + float *buffer = mlt_pool_alloc( size ); + float *p = buffer; + int32_t *q = (int32_t*) *audio; + int i = samples * channels + 1; + while ( --i ) + *p++ = (float)( *q++ ) / 2147483648.0; + *audio = buffer; + break; + } + default: + error = 1; + } + break; + case mlt_audio_float: + switch ( requested_format ) + { + case mlt_audio_s16: + { + size = channels * samples * sizeof(int16_t); + int16_t *buffer = mlt_pool_alloc( size ); + int16_t *p = buffer; + float *q = (float*) *audio; + int s, c; + for ( s = 0; s < samples; s++ ) + for ( c = 0; c < channels; c++ ) + { + float f = *( q + c * samples + s ); + f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; + *p++ = 32767 * f; + } + *audio = buffer; + break; + } + case mlt_audio_s32: + { + size = channels * samples * sizeof(int32_t); + int32_t *buffer = mlt_pool_alloc( size ); + int32_t *p = buffer; + float *q = (float*) *audio; + int i = samples * channels + 1; + while ( --i ) + { + float f = *q++; + f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; + *p++ = ( f > 0 ? 2147483647LL : 2147483648LL ) * f; + } + *audio = buffer; + break; + } + default: + error = 1; + } + break; + default: + error = 1; + } + } + if ( !error ) + { + mlt_frame_set_audio( frame, *audio, requested_format, size, mlt_pool_release ); + *format = requested_format; + } + return error; +} + +/** Filter processing. +*/ + +static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) +{ + frame->convert_audio = convert_audio; + return frame; +} + +/** Constructor for the filter. +*/ + +mlt_filter filter_audioconvert_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) +{ + mlt_filter this = calloc( sizeof( struct mlt_filter_s ), 1 ); + if ( mlt_filter_init( this, this ) == 0 ) + this->process = filter_process; + return this; +} diff --git a/src/modules/core/filter_channelcopy.c b/src/modules/core/filter_channelcopy.c index d4dd697c..6e31998f 100644 --- a/src/modules/core/filter_channelcopy.c +++ b/src/modules/core/filter_channelcopy.c @@ -20,43 +20,60 @@ #include #include +#include #include #include -#define __USE_ISOC99 1 -#include +#include /** Get the audio. */ -static int filter_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) +static int filter_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the properties of the a frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); - int i, j; + + // Get the filter service + mlt_filter filter = mlt_frame_pop_audio( frame ); + int from = mlt_properties_get_int( properties, "channelcopy.from" ); int to = mlt_properties_get_int( properties, "channelcopy.to" ); // Get the producer's audio mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); - // Duplicate channels as necessary + // Copy channels as necessary + switch ( *format ) { - int size = *channels * *samples * 2; - int16_t *new_buffer = mlt_pool_alloc( size ); - - mlt_properties_set_data( properties, "audio", new_buffer, size, ( mlt_destructor )mlt_pool_release, NULL ); - - // Duplicate the existing channels - for ( i = 0; i < *samples; i++ ) + case mlt_audio_s16: + { + int16_t *f = (int16_t*) *buffer + from; + int16_t *t = (int16_t*) *buffer + to; + int i; + for ( i = 0; i < *samples; i++, f += *channels, t += *channels ) + *t = *f; + break; + } + case mlt_audio_s32: { - for ( j = 0; j < *channels; j++ ) - { - new_buffer[ ( i * *channels ) + j ] = (*buffer)[ ( i * *channels ) + ( j == to ? from : j ) ]; - } + int32_t *f = (int32_t*) *buffer + from * *samples; + int32_t *t = (int32_t*) *buffer + to * *samples; + memcpy( t, f, *samples * sizeof(int32_t) ); + break; } - *buffer = new_buffer; + case mlt_audio_float: + { + float *f = (float*) *buffer + from * *samples; + float *t = (float*) *buffer + to * *samples; + memcpy( t, f, *samples * sizeof(float) ); + break; + } + default: + mlt_log_error( MLT_FILTER_SERVICE( filter ), "Invalid audio format\n" ); + break; } + return 0; } @@ -73,6 +90,7 @@ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) mlt_properties_set_int( frame_props, "channelcopy.from", mlt_properties_get_int( properties, "from" ) ); // Override the get_audio method + mlt_frame_push_audio( frame, this ); mlt_frame_push_audio( frame, filter_get_audio ); return frame; diff --git a/src/modules/core/filter_mono.c b/src/modules/core/filter_mono.c index 882d6f34..94d3549f 100644 --- a/src/modules/core/filter_mono.c +++ b/src/modules/core/filter_mono.c @@ -1,6 +1,6 @@ /* * filter_mono.c -- mix all channels to a mono signal across n channels - * Copyright (C) 2003-2006 Ushodaya Enterprises Limited + * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library is free software; you can redistribute it and/or @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -27,35 +28,77 @@ /** Get the audio. */ -static int filter_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) +static int filter_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the properties of the a frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); int channels_out = mlt_properties_get_int( properties, "mono.channels" ); int i, j, size; - int16_t *new_buffer; // Get the producer's audio mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); - size = *samples * channels_out * sizeof( int16_t ); - new_buffer = mlt_pool_alloc( size ); - mlt_properties_set_data( properties, "audio", new_buffer, size, ( mlt_destructor )mlt_pool_release, NULL ); + if ( channels_out == -1 ) + channels_out = *channels; + size = *samples * channels_out; - // Mix - for ( i = 0; i < *samples; i++ ) + switch ( *format ) { - int16_t mixdown = 0; - for ( j = 0; j < *channels; j++ ) - mixdown += (*buffer)[ ( i * *channels ) + j ] / *channels; - for ( j = 0; j < channels_out; j++ ) - new_buffer[ ( i * channels_out ) + j ] = mixdown; + case mlt_audio_s16: + { + size *= sizeof( int16_t ); + int16_t *new_buffer = mlt_pool_alloc( size ); + for ( i = 0; i < *samples; i++ ) + { + int16_t mixdown = 0; + for ( j = 0; j < *channels; j++ ) + mixdown += ((int16_t*) *buffer)[ ( i * *channels ) + j ] / *channels; + for ( j = 0; j < channels_out; j++ ) + new_buffer[ ( i * channels_out ) + j ] = mixdown; + } + *buffer = new_buffer; + break; + } + case mlt_audio_s32: + { + size *= sizeof( int32_t ); + int32_t *new_buffer = mlt_pool_alloc( size ); + for ( i = 0; i < *samples; i++ ) + { + int32_t mixdown = 0; + for ( j = 0; j < *channels; j++ ) + mixdown += ((int32_t*) *buffer)[ ( j * *channels ) + i ] / *channels; + for ( j = 0; j < channels_out; j++ ) + new_buffer[ ( j * *samples ) + i ] = mixdown; + } + *buffer = new_buffer; + break; + } + case mlt_audio_float: + { + size *= sizeof( float ); + float *new_buffer = mlt_pool_alloc( size ); + for ( i = 0; i < *samples; i++ ) + { + float mixdown = 0; + for ( j = 0; j < *channels; j++ ) + mixdown += ((float*) *buffer)[ ( j * *channels ) + i ] / *channels; + for ( j = 0; j < channels_out; j++ ) + new_buffer[ ( j * *samples ) + i ] = mixdown; + } + *buffer = new_buffer; + break; + } + default: + mlt_log_error( NULL, "[filter mono] Invalid audio format\n" ); + break; + } + if ( size > *samples * channels_out ) + { + mlt_frame_set_audio( frame, *buffer, *format, size, mlt_pool_release ); + *channels = channels_out; } - // Apply results - *buffer = new_buffer; - *channels = channels_out; - return 0; } @@ -88,7 +131,7 @@ mlt_filter filter_mono_init( mlt_profile profile, mlt_service_type type, const c if ( arg != NULL ) mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "channels", atoi( arg ) ); else - mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "channels", 2 ); + mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "channels", -1 ); } return this; } diff --git a/src/modules/core/filter_transition.c b/src/modules/core/filter_transition.c index cd3f4623..5515d236 100644 --- a/src/modules/core/filter_transition.c +++ b/src/modules/core/filter_transition.c @@ -39,7 +39,7 @@ static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format * NB: Not all transitions will accept a and b frames being the same... */ -static int filter_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) +static int filter_get_audio( mlt_frame this, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Obtain the transition instance mlt_transition transition = mlt_frame_pop_audio( this ); diff --git a/src/modules/core/loader.ini b/src/modules/core/loader.ini index cf7b62ec..3de7ea79 100644 --- a/src/modules/core/loader.ini +++ b/src/modules/core/loader.ini @@ -14,7 +14,8 @@ resizer=resize imageconverter=imageconvert,avcolour_space # audio filters -resampler=resample,soxresample,avresample +resampler=resample,avresample +audioconverter=audioconvert # metadata filters data=data_feed:attr_check diff --git a/src/modules/core/producer_consumer.c b/src/modules/core/producer_consumer.c index 4baa186f..c0c4019f 100644 --- a/src/modules/core/producer_consumer.c +++ b/src/modules/core/producer_consumer.c @@ -63,11 +63,24 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format return result; } -static int get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) +static int get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { mlt_frame nested_frame = mlt_frame_pop_audio( frame ); int result = mlt_frame_get_audio( nested_frame, buffer, format, frequency, channels, samples ); - int size = *channels * *samples * sizeof( int16_t ); + int size = *channels * *samples; + + switch ( *format ) + { + case mlt_audio_s16: + size *= sizeof( int16_t ); + break; + case mlt_audio_s32: + size *= sizeof( int32_t ); + case mlt_audio_float: + size *= sizeof( float ); + default: + mlt_log_error( NULL, "[producer consumer] Invalid audio format\n" ); + } int16_t *new_buffer = mlt_pool_alloc( size ); mlt_properties_set_data( MLT_FRAME_PROPERTIES( frame ), "audio", new_buffer, size, mlt_pool_release, NULL ); memcpy( new_buffer, *buffer, size ); diff --git a/src/modules/core/transition_mix.c b/src/modules/core/transition_mix.c index b2b3790a..756f9fb2 100644 --- a/src/modules/core/transition_mix.c +++ b/src/modules/core/transition_mix.c @@ -23,12 +23,147 @@ #include #include +#include +#include +static int mix_audio( mlt_frame this, mlt_frame that, float weight_start, float weight_end, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) +{ + int ret = 0; + int16_t *src, *dest; + int frequency_src = *frequency, frequency_dest = *frequency; + int channels_src = *channels, channels_dest = *channels; + int samples_src = *samples, samples_dest = *samples; + int i, j; + double d = 0, s = 0; + + mlt_frame_get_audio( that, (void**) &src, format, &frequency_src, &channels_src, &samples_src ); + mlt_frame_get_audio( this, (void**) &dest, format, &frequency_dest, &channels_dest, &samples_dest ); + + int silent = mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "silent_audio" ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES( this ), "silent_audio", 0 ); + if ( silent ) + memset( dest, 0, samples_dest * channels_dest * sizeof( int16_t ) ); + + silent = mlt_properties_get_int( MLT_FRAME_PROPERTIES( that ), "silent_audio" ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES( that ), "silent_audio", 0 ); + if ( silent ) + memset( src, 0, samples_src * channels_src * sizeof( int16_t ) ); + + if ( channels_src > 6 ) + channels_src = 0; + if ( channels_dest > 6 ) + channels_dest = 0; + if ( samples_src > 4000 ) + samples_src = 0; + if ( samples_dest > 4000 ) + samples_dest = 0; + + // determine number of samples to process + *samples = samples_src < samples_dest ? samples_src : samples_dest; + *channels = channels_src < channels_dest ? channels_src : channels_dest; + *buffer = dest; + *frequency = frequency_dest; + + // Compute a smooth ramp over start to end + float weight = weight_start; + float weight_step = ( weight_end - weight_start ) / *samples; + + if ( src == dest ) + { + *samples = samples_src; + *channels = channels_src; + *buffer = src; + *frequency = frequency_src; + return ret; + } + + // Mixdown + for ( i = 0; i < *samples; i++ ) + { + for ( j = 0; j < *channels; j++ ) + { + if ( j < channels_dest ) + d = (double) dest[ i * channels_dest + j ]; + if ( j < channels_src ) + s = (double) src[ i * channels_src + j ]; + dest[ i * channels_dest + j ] = s * weight + d * ( 1.0 - weight ); + } + weight += weight_step; + } + + return ret; +} + +// Replacement for broken mlt_frame_audio_mix - this filter uses an inline low pass filter +// to allow mixing without volume hacking +static int combine_audio( mlt_frame this, mlt_frame that, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) +{ + int ret = 0; + int16_t *src, *dest; + int frequency_src = *frequency, frequency_dest = *frequency; + int channels_src = *channels, channels_dest = *channels; + int samples_src = *samples, samples_dest = *samples; + int i, j; + double vp[ 6 ]; + double b_weight = 1.0; + + if ( mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "meta.mixdown" ) ) + b_weight = 1.0 - mlt_properties_get_double( MLT_FRAME_PROPERTIES( this ), "meta.volume" ); + + mlt_frame_get_audio( that, (void**) &src, format, &frequency_src, &channels_src, &samples_src ); + mlt_frame_get_audio( this, (void**) &dest, format, &frequency_dest, &channels_dest, &samples_dest ); + + int silent = mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "silent_audio" ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES( this ), "silent_audio", 0 ); + if ( silent ) + memset( dest, 0, samples_dest * channels_dest * sizeof( int16_t ) ); + + silent = mlt_properties_get_int( MLT_FRAME_PROPERTIES( that ), "silent_audio" ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES( that ), "silent_audio", 0 ); + if ( silent ) + memset( src, 0, samples_src * channels_src * sizeof( int16_t ) ); + + if ( src == dest ) + { + *samples = samples_src; + *channels = channels_src; + *buffer = src; + *frequency = frequency_src; + return ret; + } + + // determine number of samples to process + *samples = samples_src < samples_dest ? samples_src : samples_dest; + *channels = channels_src < channels_dest ? channels_src : channels_dest; + *buffer = dest; + *frequency = frequency_dest; + + for ( j = 0; j < *channels; j++ ) + vp[ j ] = ( double )dest[ j ]; + + double Fc = 0.5; + double B = exp(-2.0 * M_PI * Fc); + double A = 1.0 - B; + double v; + + for ( i = 0; i < *samples; i++ ) + { + for ( j = 0; j < *channels; j++ ) + { + v = ( double )( b_weight * dest[ i * channels_dest + j ] + src[ i * channels_src + j ] ); + v = v < -32767 ? -32767 : v > 32768 ? 32768 : v; + vp[ j ] = dest[ i * channels_dest + j ] = ( int16_t )( v * A + vp[ j ] * B ); + } + } + + return ret; +} + /** Get the audio. */ -static int transition_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) +static int transition_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the b frame from the stack mlt_frame b_frame = mlt_frame_pop_audio( frame ); @@ -39,6 +174,9 @@ static int transition_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_fo // Get the properties of the b frame mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame ); + // We can only mix s16 + *format = mlt_audio_s16; + if ( mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( effect ), "combine" ) == 0 ) { double mix_start = 0.5, mix_end = 0.5; @@ -52,11 +190,11 @@ static int transition_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_fo mix_end = 1 - mix_end; } - mlt_frame_mix_audio( frame, b_frame, mix_start, mix_end, buffer, format, frequency, channels, samples ); + mix_audio( frame, b_frame, mix_start, mix_end, buffer, format, frequency, channels, samples ); } else { - mlt_frame_combine_audio( frame, b_frame, buffer, format, frequency, channels, samples ); + combine_audio( frame, b_frame, buffer, format, frequency, channels, samples ); } return 0; diff --git a/src/modules/dv/consumer_libdv.c b/src/modules/dv/consumer_libdv.c index 2ee9b206..f9a8ba64 100644 --- a/src/modules/dv/consumer_libdv.c +++ b/src/modules/dv/consumer_libdv.c @@ -273,7 +273,7 @@ static void consumer_encode_audio( mlt_consumer this, uint8_t *dv_frame, mlt_fra int count = mlt_properties_get_int( this_properties, "count" ); // Default audio args - mlt_audio_format fmt = mlt_audio_pcm; + mlt_audio_format fmt = mlt_audio_s16; int channels = 2; int frequency = mlt_properties_get_int( this_properties, "frequency" ); int samples = mlt_sample_calculator( mlt_properties_get_double( this_properties, "fps" ), frequency, count ); @@ -293,7 +293,7 @@ static void consumer_encode_audio( mlt_consumer this, uint8_t *dv_frame, mlt_fra audio_buffers[ i ] = mlt_pool_alloc( 2 * DV_AUDIO_MAX_SAMPLES ); // Get the audio - mlt_frame_get_audio( frame, &pcm, &fmt, &frequency, &channels, &samples ); + mlt_frame_get_audio( frame, (void**) &pcm, &fmt, &frequency, &channels, &samples ); // Inform the encoder of the number of audio samples encoder->samples_this_frame = samples; diff --git a/src/modules/dv/producer_libdv.c b/src/modules/dv/producer_libdv.c index 6fd012c6..12501f3d 100644 --- a/src/modules/dv/producer_libdv.c +++ b/src/modules/dv/producer_libdv.c @@ -361,7 +361,7 @@ static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_forma return 0; } -static int producer_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) +static int producer_get_audio( mlt_frame this, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { int16_t *p; int i, j; @@ -382,20 +382,23 @@ static int producer_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_forma // Check that we have audio if ( decoder->audio->num_channels > 0 ) { + int size = *channels * DV_AUDIO_MAX_SAMPLES * sizeof( int16_t ); + // Obtain required values *frequency = decoder->audio->frequency; *samples = decoder->audio->samples_this_frame; *channels = decoder->audio->num_channels; + *format = mlt_audio_s16; // Create a temporary workspace for ( i = 0; i < 4; i++ ) audio_channels[ i ] = mlt_pool_alloc( DV_AUDIO_MAX_SAMPLES * sizeof( int16_t ) ); // Create a workspace for the result - *buffer = mlt_pool_alloc( *channels * DV_AUDIO_MAX_SAMPLES * sizeof( int16_t ) ); + *buffer = mlt_pool_alloc( size ); // Pass the allocated audio buffer as a property - mlt_properties_set_data( properties, "audio", *buffer, *channels * DV_AUDIO_MAX_SAMPLES * sizeof( int16_t ), ( mlt_destructor )mlt_pool_release, NULL ); + mlt_frame_set_audio( this, *buffer, *format, size, mlt_pool_release ); // Decode the audio dv_decode_full_audio( decoder, dv_data, audio_channels ); diff --git a/src/modules/jackrack/filter_jackrack.c b/src/modules/jackrack/filter_jackrack.c index 0c9fe9bf..f1b47216 100644 --- a/src/modules/jackrack/filter_jackrack.c +++ b/src/modules/jackrack/filter_jackrack.c @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -33,7 +34,7 @@ #include "jack_rack.h" -#define BUFFER_LEN 204800 * 3 +#define BUFFER_LEN 204800 * 6 static void initialise_jack_ports( mlt_properties properties ) { @@ -53,7 +54,8 @@ static void initialise_jack_ports( mlt_properties properties ) jack_rack_t *jackrack = jack_rack_new( rack_name, mlt_properties_get_int( properties, "channels" ) ); jack_rack_open_file( jackrack, mlt_properties_get( properties, "src" ) ); - mlt_properties_set_data( properties, "jackrack", jackrack, 0, NULL, NULL ); + mlt_properties_set_data( properties, "jackrack", jackrack, 0, + (mlt_destructor) jack_rack_destroy, NULL ); mlt_properties_set( properties, "_rack_client_name", rack_name ); } @@ -66,12 +68,18 @@ static void initialise_jack_ports( mlt_properties properties ) float **jack_input_buffers = mlt_pool_alloc( sizeof(float *) * jack_buffer_size ); // Set properties - released inside filter_close - mlt_properties_set_data( properties, "output_buffers", output_buffers, sizeof( jack_ringbuffer_t *) * channels, NULL, NULL ); - mlt_properties_set_data( properties, "input_buffers", input_buffers, sizeof( jack_ringbuffer_t *) * channels, NULL, NULL ); - mlt_properties_set_data( properties, "jack_output_ports", jack_output_ports, sizeof( jack_port_t *) * channels, NULL, NULL ); - mlt_properties_set_data( properties, "jack_input_ports", jack_input_ports, sizeof( jack_port_t *) * channels, NULL, NULL ); - mlt_properties_set_data( properties, "jack_output_buffers", jack_output_buffers, sizeof( float *) * channels, NULL, NULL ); - mlt_properties_set_data( properties, "jack_input_buffers", jack_input_buffers, sizeof( float *) * channels, NULL, NULL ); + mlt_properties_set_data( properties, "output_buffers", output_buffers, + sizeof( jack_ringbuffer_t *) * channels, mlt_pool_release, NULL ); + mlt_properties_set_data( properties, "input_buffers", input_buffers, + sizeof( jack_ringbuffer_t *) * channels, mlt_pool_release, NULL ); + mlt_properties_set_data( properties, "jack_output_ports", jack_output_ports, + sizeof( jack_port_t *) * channels, mlt_pool_release, NULL ); + mlt_properties_set_data( properties, "jack_input_ports", jack_input_ports, + sizeof( jack_port_t *) * channels, mlt_pool_release, NULL ); + mlt_properties_set_data( properties, "jack_output_buffers", jack_output_buffers, + sizeof( float *) * channels, mlt_pool_release, NULL ); + mlt_properties_set_data( properties, "jack_input_buffers", jack_input_buffers, + sizeof( float *) * channels, mlt_pool_release, NULL ); // Start Jack processing - required before registering ports jack_activate( jack_client ); @@ -84,9 +92,11 @@ static void initialise_jack_ports( mlt_properties properties ) output_buffers[i] = jack_ringbuffer_create( BUFFER_LEN * sizeof(float) ); input_buffers[i] = jack_ringbuffer_create( BUFFER_LEN * sizeof(float) ); snprintf( mlt_name, sizeof( mlt_name ), "obuf%d", i ); - mlt_properties_set_data( properties, mlt_name, output_buffers[i], BUFFER_LEN * sizeof(float), NULL, NULL ); + mlt_properties_set_data( properties, mlt_name, output_buffers[i], + BUFFER_LEN * sizeof(float), (mlt_destructor) jack_ringbuffer_free, NULL ); snprintf( mlt_name, sizeof( mlt_name ), "ibuf%d", i ); - mlt_properties_set_data( properties, mlt_name, input_buffers[i], BUFFER_LEN * sizeof(float), NULL, NULL ); + mlt_properties_set_data( properties, mlt_name, input_buffers[i], + BUFFER_LEN * sizeof(float), (mlt_destructor) jack_ringbuffer_free, NULL ); for ( in = 0; in < 2; in++ ) { @@ -117,12 +127,12 @@ static void initialise_jack_ports( mlt_properties properties ) if ( in ) { - fprintf( stderr, "jack connect %s to %s\n", rack_name, mlt_name ); + mlt_log_verbose( NULL, "JACK connect %s to %s\n", rack_name, mlt_name ); jack_connect( jack_client, rack_name, mlt_name ); } else { - fprintf( stderr, "jack connect %s to %s\n", mlt_name, rack_name ); + mlt_log_verbose( NULL, "JACK connect %s to %s\n", mlt_name, rack_name ); jack_connect( jack_client, mlt_name, rack_name ); } } @@ -160,7 +170,7 @@ static int jack_process (jack_nframes_t frames, void * data) jack_output_buffers[i] = jack_port_get_buffer( jack_output_ports[i], frames ); if ( ! jack_output_buffers[i] ) { - fprintf( stderr, "%s: no jack buffer for output port %d\n", __FUNCTION__, i ); + mlt_log_error( MLT_FILTER_SERVICE(filter), "no buffer for output port %d\n", i ); err = 1; break; } @@ -171,7 +181,7 @@ static int jack_process (jack_nframes_t frames, void * data) jack_input_buffers[i] = jack_port_get_buffer( jack_input_ports[i], frames ); if ( ! jack_input_buffers[i] ) { - fprintf( stderr, "%s: no jack buffer for input port %d\n", __FUNCTION__, i ); + mlt_log_error( MLT_FILTER_SERVICE(filter), "no buffer for input port %d\n", i ); err = 1; break; } @@ -179,7 +189,7 @@ static int jack_process (jack_nframes_t frames, void * data) // Do not start returning audio until we have sent first mlt frame if ( sync && i == 0 && frame_size > 0 ) total_size += ring_size; - //fprintf(stderr, "sync %d frame_size %d ring_size %d jack_size %d\n", sync, frame_size, ring_size, jack_size ); + mlt_log_debug( MLT_FILTER_SERVICE(filter), "sync %d frame_size %d ring_size %d jack_size %d\n", sync, frame_size, ring_size, jack_size ); if ( ! sync || ( frame_size > 0 && total_size >= frame_size ) ) { @@ -206,7 +216,7 @@ static int jack_process (jack_nframes_t frames, void * data) /** Get the audio. */ -static int jackrack_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) +static int jackrack_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the filter service mlt_filter filter = mlt_frame_pop_audio( frame ); @@ -217,11 +227,13 @@ static int jackrack_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form int jack_frequency = mlt_properties_get_int( filter_properties, "_sample_rate" ); // Get the producer's audio + *format = mlt_audio_float; mlt_frame_get_audio( frame, buffer, format, &jack_frequency, channels, samples ); // TODO: Deal with sample rate differences if ( *frequency != jack_frequency ) - fprintf( stderr, "mismatching frequencies in filter jackrack\n" ); + mlt_log_error( MLT_FILTER_SERVICE( filter ), "mismatching frequencies JACK = %d actual = %d\n", + jack_frequency, *frequency ); *frequency = jack_frequency; // Initialise Jack ports and connections if needed @@ -235,48 +247,27 @@ static int jackrack_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form // pthread_cond_t *output_ready = mlt_properties_get_data( filter_properties, "output_ready", NULL ); // Process the audio - int16_t *q = *buffer; - float sample[ 2 ][ 10000 ]; - int i, j; + float *q = (float*) *buffer; + size_t size = *samples * sizeof(float); + int j; // struct timespec tm = { 0, 0 }; - // Convert to floats and write into output ringbuffer - if ( jack_ringbuffer_write_space( output_buffers[0] ) >= ( *samples * sizeof(float) ) ) + // Write into output ringbuffer + for ( j = 0; j < *channels; j++ ) { - for ( i = 0; i < *samples; i++ ) - for ( j = 0; j < *channels; j++ ) - sample[ j ][ i ] = ( float )( *q ++ ) / 32768.0; - - for ( j = 0; j < *channels; j++ ) - jack_ringbuffer_write( output_buffers[j], ( char * )sample[ j ], *samples * sizeof(float) ); + if ( jack_ringbuffer_write_space( output_buffers[j] ) >= size ) + jack_ringbuffer_write( output_buffers[j], (char*)( q + j * *samples ), size ); } // Synchronization phase - wait for signal from Jack process - while ( jack_ringbuffer_read_space( input_buffers[ *channels - 1 ] ) < ( *samples * sizeof(float) ) ) ; + while ( jack_ringbuffer_read_space( input_buffers[ *channels - 1 ] ) < size ) ; //pthread_cond_wait( output_ready, output_lock ); - // Read from input ringbuffer and convert from floats - if ( jack_ringbuffer_read_space( input_buffers[0] ) >= ( *samples * sizeof(float) ) ) + // Read from input ringbuffer + for ( j = 0; j < *channels; j++, q++ ) { - // Initialise to silence, but repeat last frame if available in case of - // buffer underrun - for ( j = 0; j < *channels; j++ ) - jack_ringbuffer_read( input_buffers[j], ( char * )sample[ j ], *samples * sizeof(float) ); - - q = *buffer; - for ( i = 0; i < *samples; i++ ) - for ( j = 0; j < *channels; j++ ) - { - if ( sample[ j ][ i ] > 1.0 ) - sample[ j ][ i ] = 1.0; - else if ( sample[ j ][ i ] < -1.0 ) - sample[ j ][ i ] = -1.0; - - if ( sample[ j ][ i ] > 0 ) - *q ++ = 32767 * sample[ j ][ i ]; - else - *q ++ = 32768 * sample[ j ][ i ]; - } + if ( jack_ringbuffer_read_space( input_buffers[j] ) >= size ) + jack_ringbuffer_read( input_buffers[j], (char*)( q + j * *samples ), size ); } return 0; @@ -293,7 +284,7 @@ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) mlt_frame_push_audio( frame, this ); mlt_frame_push_audio( frame, jackrack_get_audio ); - if ( mlt_properties_get_int( properties, "_sync" ) ) + if ( !mlt_properties_get_data( properties, "jackrack", NULL ) ) initialise_jack_ports( properties ); } @@ -303,32 +294,10 @@ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) static void filter_close( mlt_filter this ) { - int i; - char mlt_name[20]; mlt_properties properties = MLT_FILTER_PROPERTIES( this ); jack_client_t *jack_client = mlt_properties_get_data( properties, "jack_client", NULL ); - jack_deactivate( jack_client ); jack_client_close( jack_client ); - for ( i = 0; i < mlt_properties_get_int( properties, "channels" ); i++ ) - { - snprintf( mlt_name, sizeof( mlt_name ), "obuf%d", i ); - jack_ringbuffer_free( mlt_properties_get_data( properties, mlt_name, NULL ) ); - snprintf( mlt_name, sizeof( mlt_name ), "ibuf%d", i ); - jack_ringbuffer_free( mlt_properties_get_data( properties, mlt_name, NULL ) ); - } - mlt_pool_release( mlt_properties_get_data( properties, "output_buffers", NULL ) ); - mlt_pool_release( mlt_properties_get_data( properties, "input_buffers", NULL ) ); - mlt_pool_release( mlt_properties_get_data( properties, "jack_output_ports", NULL ) ); - mlt_pool_release( mlt_properties_get_data( properties, "jack_input_ports", NULL ) ); - mlt_pool_release( mlt_properties_get_data( properties, "jack_output_buffers", NULL ) ); - mlt_pool_release( mlt_properties_get_data( properties, "jack_input_buffers", NULL ) ); - mlt_pool_release( mlt_properties_get_data( properties, "output_lock", NULL ) ); - mlt_pool_release( mlt_properties_get_data( properties, "output_ready", NULL ) ); - - jack_rack_t *jackrack = mlt_properties_get_data( properties, "jackrack", NULL ); - jack_rack_destroy( jackrack ); - this->parent.close = NULL; mlt_service_close( &this->parent ); } @@ -362,8 +331,8 @@ mlt_filter filter_jackrack_init( mlt_profile profile, mlt_service_type type, con mlt_properties_set( properties, "_client_name", name ); mlt_properties_set_data( properties, "jack_client", jack_client, 0, NULL, NULL ); mlt_properties_set_int( properties, "_sample_rate", jack_get_sample_rate( jack_client ) ); - mlt_properties_set_data( properties, "output_lock", output_lock, 0, NULL, NULL ); - mlt_properties_set_data( properties, "output_ready", output_ready, 0, NULL, NULL ); + mlt_properties_set_data( properties, "output_lock", output_lock, 0, mlt_pool_release, NULL ); + mlt_properties_set_data( properties, "output_ready", output_ready, 0, mlt_pool_release, NULL ); mlt_properties_set_int( properties, "_sync", 1 ); mlt_properties_set_int( properties, "channels", 2 ); } diff --git a/src/modules/jackrack/filter_ladspa.c b/src/modules/jackrack/filter_ladspa.c index 7eff6fab..02f427a0 100644 --- a/src/modules/jackrack/filter_ladspa.c +++ b/src/modules/jackrack/filter_ladspa.c @@ -33,49 +33,33 @@ #define BUFFER_LEN 10000 -static void initialise_jack_rack( mlt_properties properties, int channels ) +static jack_rack_t* initialise_jack_rack( mlt_properties properties, int channels ) { - int i; - char mlt_name[20]; - + jack_rack_t *jackrack = NULL; + char *resource = mlt_properties_get( properties, "resource" ); + if ( !resource && mlt_properties_get( properties, "src" ) ) + resource = mlt_properties_get( properties, "src" ); + // Propogate these for the Jack processing callback mlt_properties_set_int( properties, "channels", channels ); // Start JackRack - if ( mlt_properties_get( properties, "src" ) ) + if ( resource ) { // Create JackRack without Jack client name so that it only uses LADSPA - jack_rack_t *jackrack = jack_rack_new( NULL, channels ); - mlt_properties_set_data( properties, "jackrack", jackrack, 0, NULL, NULL ); - jack_rack_open_file( jackrack, mlt_properties_get( properties, "src" ) ); - } - - // Allocate buffers - LADSPA_Data **input_buffers = mlt_pool_alloc( sizeof( LADSPA_Data ) * channels ); - LADSPA_Data **output_buffers = mlt_pool_alloc( sizeof( LADSPA_Data ) * channels ); - - // Set properties - released inside filter_close - mlt_properties_set_data( properties, "input_buffers", input_buffers, sizeof( LADSPA_Data *) * channels, NULL, NULL ); - mlt_properties_set_data( properties, "output_buffers", output_buffers, sizeof( LADSPA_Data *) * channels, NULL, NULL ); - - // Register Jack ports - for ( i = 0; i < channels; i++ ) - { - input_buffers[i] = mlt_pool_alloc( BUFFER_LEN * sizeof( LADSPA_Data ) ); - snprintf( mlt_name, sizeof( mlt_name ), "ibuf%d", i ); - mlt_properties_set_data( properties, mlt_name, input_buffers[i], BUFFER_LEN * sizeof( LADSPA_Data ), NULL, NULL ); - - output_buffers[i] = mlt_pool_alloc( BUFFER_LEN * sizeof( LADSPA_Data ) ); - snprintf( mlt_name, sizeof( mlt_name ), "obuf%d", i ); - mlt_properties_set_data( properties, mlt_name, output_buffers[i], BUFFER_LEN * sizeof( LADSPA_Data ), NULL, NULL ); + jackrack = jack_rack_new( NULL, channels ); + mlt_properties_set_data( properties, "jackrack", jackrack, 0, + (mlt_destructor) jack_rack_destroy, NULL ); + jack_rack_open_file( jackrack, resource ); } + return jackrack; } /** Get the audio. */ -static int ladspa_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) +static int ladspa_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the filter service mlt_filter filter = mlt_frame_pop_audio( frame ); @@ -84,51 +68,35 @@ static int ladspa_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); // Get the producer's audio + *format = mlt_audio_float; mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); // Initialise LADSPA if needed jack_rack_t *jackrack = mlt_properties_get_data( filter_properties, "jackrack", NULL ); if ( jackrack == NULL ) { - sample_rate = *frequency; - initialise_jack_rack( filter_properties, *channels ); - jackrack = mlt_properties_get_data( filter_properties, "jackrack", NULL ); + sample_rate = *frequency; // global inside jack_rack + jackrack = initialise_jack_rack( filter_properties, *channels ); } // Get the filter-specific properties - LADSPA_Data **input_buffers = mlt_properties_get_data( filter_properties, "input_buffers", NULL ); - LADSPA_Data **output_buffers = mlt_properties_get_data( filter_properties, "output_buffers", NULL ); - - // Process the audio - int16_t *q = *buffer; - int i, j; + LADSPA_Data **input_buffers = mlt_pool_alloc( sizeof( LADSPA_Data* ) * *channels ); + LADSPA_Data **output_buffers = mlt_pool_alloc( sizeof( LADSPA_Data* ) * *channels ); - // Convert to floats and write into output ringbuffer - for ( i = 0; i < *samples; i++ ) - for ( j = 0; j < *channels; j++ ) - input_buffers[ j ][ i ] = ( float )( *q ++ ) / 32768.0; - - // Do LADSPA processing - if ( jackrack && process_ladspa( jackrack->procinfo, *samples, input_buffers, output_buffers) == 0 ) + int i; + for ( i = 0; i < *channels; i++ ) { - // Read from output buffer and convert from floats - q = *buffer; - for ( i = 0; i < *samples; i++ ) - for ( j = 0; j < *channels; j++ ) - { - if ( output_buffers[ j ][ i ] > 1.0 ) - output_buffers[ j ][ i ] = 1.0; - else if ( output_buffers[ j ][ i ] < -1.0 ) - output_buffers[ j ][ i ] = -1.0; - - if ( output_buffers[ j ][ i ] > 0 ) - *q ++ = 32767 * output_buffers[ j ][ i ]; - else - *q ++ = 32768 * output_buffers[ j ][ i ]; - } + input_buffers[i] = (LADSPA_Data*) *buffer + i * *samples; + output_buffers[i] = (LADSPA_Data*) *buffer + i * *samples; } - return 0; + // Do LADSPA processing + int error = jackrack && process_ladspa( jackrack->procinfo, *samples, input_buffers, output_buffers ); + + mlt_pool_release( input_buffers ); + mlt_pool_release( output_buffers ); + + return error; } @@ -137,6 +105,7 @@ static int ladspa_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { + if ( mlt_frame_is_test_audio( frame ) == 0 ) { mlt_frame_push_audio( frame, this ); mlt_frame_push_audio( frame, ladspa_get_audio ); @@ -145,32 +114,6 @@ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) return frame; } - -static void filter_close( mlt_filter this ) -{ - int i; - char mlt_name[20]; - mlt_properties properties = MLT_FILTER_PROPERTIES( this ); - - if ( mlt_properties_get_data( properties, "jackrack", NULL ) != NULL ) - { - for ( i = 0; i < mlt_properties_get_int( properties, "channels" ); i++ ) - { - snprintf( mlt_name, sizeof( mlt_name ), "obuf%d", i ); - mlt_pool_release( mlt_properties_get_data( properties, mlt_name, NULL ) ); - snprintf( mlt_name, sizeof( mlt_name ), "ibuf%d", i ); - mlt_pool_release( mlt_properties_get_data( properties, mlt_name, NULL ) ); - } - mlt_pool_release( mlt_properties_get_data( properties, "output_buffers", NULL ) ); - mlt_pool_release( mlt_properties_get_data( properties, "input_buffers", NULL ) ); - - jack_rack_t *jackrack = mlt_properties_get_data( properties, "jackrack", NULL ); - jack_rack_destroy( jackrack ); - } - this->parent.close = NULL; - mlt_service_close( &this->parent ); -} - /** Constructor for the filter. */ @@ -180,11 +123,8 @@ mlt_filter filter_ladspa_init( mlt_profile profile, mlt_service_type type, const if ( this != NULL ) { mlt_properties properties = MLT_FILTER_PROPERTIES( this ); - this->process = filter_process; - this->close = filter_close; - - mlt_properties_set( properties, "src", arg ); + mlt_properties_set( properties, "resource", arg ); } return this; } diff --git a/src/modules/normalize/filter_volume.c b/src/modules/normalize/filter_volume.c index 3bc747ce..e73eef33 100644 --- a/src/modules/normalize/filter_volume.c +++ b/src/modules/normalize/filter_volume.c @@ -163,7 +163,7 @@ double signal_max_power( int16_t *buffer, int channels, int samples, int16_t *pe /** Get the audio. */ -static int filter_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) +static int filter_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the properties of the a frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); @@ -186,6 +186,7 @@ static int filter_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format limiter_level = mlt_properties_get_double( properties, "volume.limiter" ); // Get the producer's audio + *format = mlt_audio_s16; mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); // fprintf( stderr, "filter_volume: frequency %d\n", *frequency ); @@ -217,7 +218,7 @@ static int filter_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format } else { - gain *= amplitude / signal_max_power( *buffer, *channels, *samples, &peak ); + gain *= amplitude / signal_max_power( (int16_t*) *buffer, *channels, *samples, &peak ); } } @@ -248,7 +249,7 @@ static int filter_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format // Ramp from the previous gain to the current gain = previous_gain; - int16_t *p = *buffer; + int16_t *p = (int16_t*) *buffer; // Apply the gain for ( i = 0; i < *samples; i++ ) diff --git a/src/modules/resample/filter_resample.c b/src/modules/resample/filter_resample.c index 9ff4d9e1..8a4543ee 100644 --- a/src/modules/resample/filter_resample.c +++ b/src/modules/resample/filter_resample.c @@ -20,10 +20,12 @@ #include #include +#include #include #include #include +#include #define BUFFER_LEN 20480 #define RESAMPLE_TYPE SRC_SINC_FASTEST @@ -31,11 +33,8 @@ /** 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 ); @@ -44,113 +43,88 @@ static int resample_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form // 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; + int error = 0; // 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; - } + if ( *format != mlt_audio_s16 ) + *format = mlt_audio_float; + mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); // Return now if no work to do if ( output_rate != *frequency ) { - float *p = input_buffer; - float *end = p + *samples * *channels; - int16_t *q = *buffer; - - // Convert to floating point - while( p != end ) - *p ++ = ( float )( *q ++ ) / 32768.0; - - // Resample + // Do not convert to float unless we need to change the rate + if ( *format != mlt_audio_float ) + { + *format = mlt_audio_float; + mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); + } + float *input_buffer = mlt_properties_get_data( filter_properties, "input_buffer", NULL ); + float *output_buffer = mlt_properties_get_data( filter_properties, "output_buffer", NULL ); + SRC_DATA data; data.data_in = input_buffer; data.data_out = output_buffer; 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 ) + { + // 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 ); + } + + // Convert to interleaved + float *q = (float*) *buffer; + float *p = input_buffer; + int s, c; + for ( s = 0; s < *samples; s++ ) + for ( c = 0; c < *channels; c++ ) + *p++ = *( q + c * *samples + s ); + + // Resample the audio + error = src_process( state, &data ); + if ( !error ) { + int size = data.output_frames_gen * *channels * sizeof(float); + + // Resize if necessary 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 ); + *buffer = mlt_pool_realloc( *buffer, size ); + mlt_frame_set_audio( frame, *buffer, *format, size, mlt_pool_release ); } - *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 ) + // Convert to non-interleaved + p = (float*) *buffer; + for ( c = 0; c < *channels; c++ ) { - if ( *p > 1.0 ) - *p = 1.0; - if ( *p < -1.0 ) - *p = -1.0; - if ( *p > 0 ) - *q ++ = 32767 * *p ++; - else - *q ++ = 32768 * *p ++; + float *q = output_buffer + c; + int i = data.output_frames_gen + 1; + while ( --i ) + { + *p++ = *q; + q += *channels; + } } + + // Update output variables + *samples = data.output_frames_gen; + *frequency = output_rate; } 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 ); } - return 0; + return error; } /** Filter processing. diff --git a/src/modules/sdl/consumer_sdl.c b/src/modules/sdl/consumer_sdl.c index 63ef5405..42582c6d 100644 --- a/src/modules/sdl/consumer_sdl.c +++ b/src/modules/sdl/consumer_sdl.c @@ -342,7 +342,7 @@ static int consumer_play_audio( consumer_sdl this, mlt_frame frame, int init_aud { // Get the properties of this consumer mlt_properties properties = this->properties; - mlt_audio_format afmt = mlt_audio_pcm; + mlt_audio_format afmt = mlt_audio_s16; // Set the preferred params of the test card signal int channels = mlt_properties_get_int( properties, "channels" ); @@ -354,7 +354,7 @@ static int consumer_play_audio( consumer_sdl this, mlt_frame frame, int init_aud int16_t *pcm; int bytes; - mlt_frame_get_audio( frame, &pcm, &afmt, &frequency, &channels, &samples ); + mlt_frame_get_audio( frame, (void**) &pcm, &afmt, &frequency, &channels, &samples ); *duration = ( ( samples * 1000 ) / frequency ); if ( mlt_properties_get_int( properties, "audio_off" ) ) diff --git a/src/modules/sox/filter_sox.c b/src/modules/sox/filter_sox.c index d2ef2d24..861c0d2c 100644 --- a/src/modules/sox/filter_sox.c +++ b/src/modules/sox/filter_sox.c @@ -179,14 +179,11 @@ static int create_effect( mlt_filter this, char *value, int count, int channel, /** Get the audio. */ -static int filter_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) +static int filter_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { #if (ST_LIB_VERSION_CODE >= ST_LIB_VERSION(14,3,0)) SOX_SAMPLE_LOCALS; #endif - // 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 ); @@ -194,55 +191,14 @@ static int filter_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); // Get the properties - st_sample_t *input_buffer = mlt_properties_get_data( filter_properties, "input_buffer", NULL ); + st_sample_t *input_buffer;// = mlt_properties_get_data( filter_properties, "input_buffer", NULL ); st_sample_t *output_buffer = mlt_properties_get_data( filter_properties, "output_buffer", NULL ); - int channels_avail = *channels; int i; // channel int count = mlt_properties_get_int( filter_properties, "_effect_count" ); // 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; - } + *format = mlt_audio_s32; + mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); // Even though some effects are multi-channel aware, it is not reliable // We must maintain a separate effect state for each channel @@ -296,32 +252,21 @@ static int filter_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format } if ( *samples > 0 && count > 0 ) { + input_buffer = (st_sample_t*) *buffer + i * *samples; st_sample_t *p = input_buffer; - st_sample_t *end = p + *samples; - int16_t *q = *buffer + i; st_size_t isamp = *samples; st_size_t osamp = *samples; double rms = 0; - int j; + int j = *samples + 1; char *normalise = mlt_properties_get( filter_properties, "normalise" ); double normalised_gain = 1.0; -#if (ST_LIB_VERSION_CODE >= ST_LIB_VERSION(13,0,0)) - st_sample_t dummy_clipped_count = 0; -#endif - // Convert to sox encoding - while( p != end ) + // Convert from interleaved + while( --j ) { -#if (ST_LIB_VERSION_CODE >= ST_LIB_VERSION(13,0,0)) - *p = ST_SIGNED_WORD_TO_SAMPLE( *q, dummy_clipped_count ); -#else - *p = ST_SIGNED_WORD_TO_SAMPLE( *q ); -#endif // Compute rms amplitude while we are accessing each sample rms += ( double )*p * ( double )*p; - p ++; - q += *channels; } // Compute final rms amplitude @@ -411,20 +356,9 @@ static int filter_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format } } } - - // Convert back to signed 16bit - p = input_buffer; - q = *buffer + i; - end = p + *samples; - while ( p != end ) - { -#if (ST_LIB_VERSION_CODE >= ST_LIB_VERSION(13,0,0)) - *q = ST_SAMPLE_TO_SIGNED_WORD( *p ++, dummy_clipped_count ); -#else - *q = ST_SAMPLE_TO_SIGNED_WORD( *p ++ ); -#endif - q += *channels; - } + + // Write back + memcpy( output_buffer, input_buffer, *samples * sizeof(st_sample_t) ); } } diff --git a/src/modules/vorbis/producer_vorbis.c b/src/modules/vorbis/producer_vorbis.c index 1c1e7ced..77f92166 100644 --- a/src/modules/vorbis/producer_vorbis.c +++ b/src/modules/vorbis/producer_vorbis.c @@ -206,7 +206,7 @@ static double producer_time_of_frame( mlt_producer this, mlt_position position ) /** Get the audio from a frame. */ -static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) +static int producer_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the properties from the frame mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); @@ -314,11 +314,14 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form // Now handle the audio if we have enough if ( audio_used >= *samples ) { - *buffer = mlt_pool_alloc( *samples * *channels * sizeof( int16_t ) ); - memcpy( *buffer, audio_buffer, *samples * *channels * sizeof( int16_t ) ); + int size = *samples * *channels * sizeof( int16_t ); + + *format = mlt_audio_s16; + *buffer = mlt_pool_alloc( size ); + memcpy( *buffer, audio_buffer, size ); audio_used -= *samples; memmove( audio_buffer, &audio_buffer[ *samples * *channels ], audio_used * *channels * sizeof( int16_t ) ); - mlt_properties_set_data( frame_properties, "audio", *buffer, 0, mlt_pool_release, NULL ); + mlt_frame_set_audio( frame, *buffer, *format, size, mlt_pool_release ); } else {