From 4bb099f9f13875393e0392a49be0e49de18ef5cc Mon Sep 17 00:00:00 2001 From: ddennedy Date: Tue, 25 Nov 2008 03:32:21 +0000 Subject: [PATCH] producer_avformat.c: bugfix (kdenlive-297) audio distortion with audio formats other than signed 16-bit. git-svn-id: https://mlt.svn.sourceforge.net/svnroot/mlt/trunk/mlt@1242 d19143bc-622f-0410-bfdd-b5b2a6649095 --- src/modules/avformat/audioconvert.h | 111 ++++++++++++++++++++++++++++++ src/modules/avformat/producer_avformat.c | 90 +++++++++++++++++++++---- 2 files changed, 188 insertions(+), 13 deletions(-) create mode 100644 src/modules/avformat/audioconvert.h diff --git a/src/modules/avformat/audioconvert.h b/src/modules/avformat/audioconvert.h new file mode 100644 index 0000000..4b76710 --- /dev/null +++ b/src/modules/avformat/audioconvert.h @@ -0,0 +1,111 @@ +/* + * audio conversion + * Copyright (c) 2006 Michael Niedermayer + * Copyright (c) 2008 Peter Ross + * + * This file is part of FFmpeg. + * + * FFmpeg 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. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AUDIOCONVERT_H +#define AVCODEC_AUDIOCONVERT_H + +/** + * @file audioconvert.h + * Audio format conversion routines + */ + + +#include "avcodec.h" + + +/** + * Generate string corresponding to the sample format with + * number sample_fmt, or a header if sample_fmt is negative. + * + * @param[in] buf the buffer where to write the string + * @param[in] buf_size the size of buf + * @param[in] sample_fmt the number of the sample format to print the corresponding info string, or + * a negative value to print the corresponding header. + * Meaningful values for obtaining a sample format info vary from 0 to SAMPLE_FMT_NB -1. + */ +void avcodec_sample_fmt_string(char *buf, int buf_size, int sample_fmt); + +/** + * @return NULL on error + */ +const char *avcodec_get_sample_fmt_name(int sample_fmt); + +/** + * @return SAMPLE_FMT_NONE on error + */ +enum SampleFormat avcodec_get_sample_fmt(const char* name); + +/** + * @return NULL on error + */ +const char *avcodec_get_channel_name(int channel_id); + +/** + * Return description of channel layout + */ +void avcodec_get_channel_layout_string(char *buf, int buf_size, int nb_channels, int64_t channel_layout); + +/** + * Guess the channel layout + * @param nb_channels + * @param codec_id Codec identifier, or CODEC_ID_NONE if unknown + * @param fmt_name Format name, or NULL if unknown + * @return Channel layout mask + */ +int64_t avcodec_guess_channel_layout(int nb_channels, enum CodecID codec_id, const char *fmt_name); + + +struct AVAudioConvert; +typedef struct AVAudioConvert AVAudioConvert; + +/** + * Create an audio sample format converter context + * @param out_fmt Output sample format + * @param out_channels Number of output channels + * @param in_fmt Input sample format + * @param in_channels Number of input channels + * @param[in] matrix Channel mixing matrix (of dimension in_channel*out_channels). Set to NULL to ignore. + * @param flags See FF_MM_xx + * @return NULL on error + */ +AVAudioConvert *av_audio_convert_alloc(enum SampleFormat out_fmt, int out_channels, + enum SampleFormat in_fmt, int in_channels, + const float *matrix, int flags); + +/** + * Free audio sample format converter context + */ +void av_audio_convert_free(AVAudioConvert *ctx); + +/** + * Convert between audio sample formats + * @param[in] out array of output buffers for each channel. set to NULL to ignore processing of the given channel. + * @param[in] out_stride distance between consecutive input samples (measured in bytes) + * @param[in] in array of input buffers for each channel + * @param[in] in_stride distance between consecutive output samples (measured in bytes) + * @param len length of audio frame size (measured in samples) + */ +int av_audio_convert(AVAudioConvert *ctx, + void * const out[6], const int out_stride[6], + const void * const in[6], const int in_stride[6], int len); + +#endif /* AVCODEC_AUDIOCONVERT_H */ diff --git a/src/modules/avformat/producer_avformat.c b/src/modules/avformat/producer_avformat.c index 1349fe0..4039d1e 100644 --- a/src/modules/avformat/producer_avformat.c +++ b/src/modules/avformat/producer_avformat.c @@ -26,7 +26,10 @@ // ffmpeg Header files #include #ifdef SWSCALE -#include +# include +#endif +#if (LIBAVCODEC_VERSION_INT >= ((51<<16)+(71<<8)+0)) +# include "audioconvert.h" #endif // System header files @@ -964,8 +967,15 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form // Obtain the resample context if it exists (not always needed) ReSampleContext *resample = mlt_properties_get_data( properties, "audio_resample", NULL ); - // Obtain the audio buffer +#if (LIBAVCODEC_VERSION_INT >= ((51<<16)+(71<<8)+0)) + // Get the format converter context if it exists + AVAudioConvert *convert = mlt_properties_get_data( properties, "audio_convert", NULL ); +#endif + + // Obtain the audio buffers int16_t *audio_buffer = mlt_properties_get_data( properties, "audio_buffer", NULL ); + int16_t *decode_buffer = mlt_properties_get_data( properties, "decode_buffer", NULL ); + int16_t *convert_buffer = mlt_properties_get_data( properties, "convert_buffer", NULL ); // Get amount of audio used int audio_used = mlt_properties_get_int( properties, "_audio_used" ); @@ -989,7 +999,7 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form int paused = 0; // Check for resample and create if necessary - if ( resample == NULL && codec_context->channels <= 2 ) + if ( resample == NULL && ( *frequency != codec_context->sample_rate || codec_context->channels <= 2 ) ) { // Create the resampler resample = audio_resample_init( *channels, codec_context->channels, *frequency, codec_context->sample_rate ); @@ -1003,6 +1013,17 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form *frequency = codec_context->sample_rate; } +#if (LIBAVCODEC_VERSION_INT >= ((51<<16)+(71<<8)+0)) + // Check for audio format converter and create if necessary + // TODO: support higher resolutions than 16-bit. + if ( convert == NULL && codec_context->sample_fmt != SAMPLE_FMT_S16 ) + { + // Create single channel converter for interleaved with no mixing matrix + convert = av_audio_convert_alloc( SAMPLE_FMT_S16, 1, codec_context->sample_fmt, 1, NULL, 0 ); + mlt_properties_set_data( properties, "audio_convert", convert, 0, ( mlt_destructor )av_audio_convert_free, NULL ); + } +#endif + // Check for audio buffer and create if necessary if ( audio_buffer == NULL ) { @@ -1013,6 +1034,26 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form mlt_properties_set_data( properties, "audio_buffer", audio_buffer, 0, ( mlt_destructor )mlt_pool_release, NULL ); } + // Check for decoder buffer and create if necessary + if ( decode_buffer == NULL ) + { + // Allocate the audio buffer + decode_buffer = mlt_pool_alloc( AVCODEC_MAX_AUDIO_FRAME_SIZE * sizeof( int16_t ) ); + + // And store it on properties for reuse + mlt_properties_set_data( properties, "decode_buffer", decode_buffer, 0, ( mlt_destructor )mlt_pool_release, NULL ); + } + + // Check for format converter buffer and create if necessary + if ( resample && convert && convert_buffer == NULL ) + { + // Allocate the audio buffer + convert_buffer = mlt_pool_alloc( AVCODEC_MAX_AUDIO_FRAME_SIZE * sizeof( int16_t ) ); + + // And store it on properties for reuse + mlt_properties_set_data( properties, "convert_buffer", convert_buffer, 0, ( mlt_destructor )mlt_pool_release, NULL ); + } + // Seek if necessary if ( position != expected ) { @@ -1042,7 +1083,6 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form { int ret = 0; int got_audio = 0; - int16_t *temp = av_malloc( sizeof( int16_t ) * AVCODEC_MAX_AUDIO_FRAME_SIZE ); av_init_packet( &pkt ); @@ -1068,9 +1108,9 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form // Decode the audio #if (LIBAVCODEC_VERSION_INT >= ((51<<16)+(29<<8)+0)) - ret = avcodec_decode_audio2( codec_context, temp, &data_size, ptr, len ); + ret = avcodec_decode_audio2( codec_context, decode_buffer, &data_size, ptr, len ); #else - ret = avcodec_decode_audio( codec_context, temp, &data_size, ptr, len ); + ret = avcodec_decode_audio( codec_context, decode_buffer, &data_size, ptr, len ); #endif if ( ret < 0 ) { @@ -1083,14 +1123,41 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form if ( data_size > 0 ) { - if ( resample != NULL ) + int src_stride[6]= { av_get_bits_per_sample_format( codec_context->sample_fmt ) / 8 }; + int dst_stride[6]= { av_get_bits_per_sample_format( SAMPLE_FMT_S16 ) / 8 }; + + if ( resample ) { - audio_used += audio_resample( resample, &audio_buffer[ audio_used * *channels ], temp, data_size / ( codec_context->channels * sizeof( int16_t ) ) ); + int16_t *source = decode_buffer; + int16_t *dest = &audio_buffer[ audio_used * *channels ]; + int convert_samples = data_size / src_stride[0]; + +#if (LIBAVCODEC_VERSION_INT >= ((51<<16)+(71<<8)+0)) + if ( convert ) + { + const void *src_buf[6] = { decode_buffer }; + void *dst_buf[6] = { convert_buffer }; + av_audio_convert( convert, dst_buf, dst_stride, src_buf, src_stride, convert_samples ); + source = convert_buffer; + } +#endif + audio_used += audio_resample( resample, dest, source, convert_samples / codec_context->channels ); } else { - memcpy( &audio_buffer[ audio_used * *channels ], temp, data_size ); - audio_used += data_size / ( codec_context->channels * sizeof( int16_t ) ); +#if (LIBAVCODEC_VERSION_INT >= ((51<<16)+(71<<8)+0)) + if ( convert ) + { + const void *src_buf[6] = { decode_buffer }; + void *dst_buf[6] = { &audio_buffer[ audio_used * *channels ] }; + av_audio_convert( convert, dst_buf, dst_stride, src_buf, src_stride, data_size / src_stride[0] ); + } + else +#endif + { + memcpy( &audio_buffer[ audio_used * *channels ], decode_buffer, data_size ); + } + audio_used += data_size / *channels / src_stride[0]; } // Handle ignore @@ -1132,9 +1199,6 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form // Store the number of audio samples still available mlt_properties_set_int( properties, "_audio_used", audio_used ); - - // Release the temporary audio - av_free( temp ); } else { -- 1.7.4.4