From 36de2c64d497e94d12acecbd6b00f3660f626850 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 4 Jun 2014 18:26:12 +0200 Subject: [PATCH 1/5] Add AudioTransform: convert samples * AudioTransform: does the same process as ColorTransform, but applied to audio. * AudioDesc: add a function to get a FrameDesc. * AudioRewrapper: use AudioTransform. --- app/SConscript | 1 + app/audioRewrapper/audioRewrapper.cpp | 57 ++++++++------ src/AvTranscoder/AudioTransform.cpp | 74 +++++++++++++++++++ src/AvTranscoder/AudioTransform.hpp | 30 ++++++++ .../DatasStructures/AudioDesc.cpp | 12 +++ .../DatasStructures/AudioDesc.hpp | 4 + 6 files changed, 156 insertions(+), 22 deletions(-) create mode 100644 src/AvTranscoder/AudioTransform.cpp create mode 100644 src/AvTranscoder/AudioTransform.hpp diff --git a/app/SConscript b/app/SConscript index 8070a012..8a36c3a6 100644 --- a/app/SConscript +++ b/app/SConscript @@ -69,6 +69,7 @@ audioRewrapper = env.Program( 'avformat', 'avcodec', 'swscale', + 'swresample', ] ) diff --git a/app/audioRewrapper/audioRewrapper.cpp b/app/audioRewrapper/audioRewrapper.cpp index 2310bdea..e886347c 100644 --- a/app/audioRewrapper/audioRewrapper.cpp +++ b/app/audioRewrapper/audioRewrapper.cpp @@ -2,11 +2,15 @@ #include #include +#include + #include #include #include -#include +#include + + void rewrapAudio( const char* inputfilename, const char* outputFilename ) { @@ -52,56 +56,65 @@ void transcodeAudio( const char* inputfilename, const char* outputFilename ) InputFile inputFile( inputfilename ); inputFile.analyse(); + OutputFile outputFile( outputFilename ); + outputFile.setup(); + // init audio decoders InputStreamAudio inputStreamAudio( inputFile.getStream( 0 ) ); inputFile.getStream( 0 ).setBufferred( true ); - - OutputFile outputFile( outputFilename ); - outputFile.setup(); - outputFile.addAudioStream( inputFile.getStream( 0 ).getAudioDesc() ); - outputFile.beginWrap(); + // init audio encoders OutputStreamAudio outputStreamAudio; AudioDesc& audioDesc = outputStreamAudio.getAudioDesc(); - audioDesc.setAudioCodec( "pcm_s16le" ); + audioDesc.setAudioCodec( "pcm_s24le" ); audioDesc.setAudioParameters( inputFile.getStream( 0 ).getAudioDesc().getSampleRate(), inputFile.getStream( 0 ).getAudioDesc().getChannels(), - inputFile.getStream( 0 ).getAudioDesc().getSampleFormat() + AV_SAMPLE_FMT_S32//,inputFile.getStream( 0 ).getAudioDesc().getSampleFormat() ); - DataStream codedFrame; - if( ! outputStreamAudio.setup( ) ) { std::cout << "error during initialising audio output stream" << std::endl; exit( -1 ); } - // Transcoding - std::cout << "start transcoding" << std::endl; + outputFile.addAudioStream( audioDesc ); + outputFile.beginWrap(); + + // init convert + AudioTransform audioTransform; + + DataStream codedFrame; + // start transcoding process + std::cout << "start transcoding" << std::endl; + + AudioFrame audioFrameSource( inputFile.getStream( 0 ).getAudioDesc().getFrameDesc() ); + AudioFrame audioFrameToEncode( audioDesc.getFrameDesc() ); + size_t frame = 0; - AudioFrameDesc audioFrameDesc; - - AudioFrame audioFrame( audioFrameDesc ); - - while( inputStreamAudio.readNextFrame( audioFrame ) ) + while( inputStreamAudio.readNextFrame( audioFrameSource ) ) { - std::cout << "\rprocess frame " << (int)frame - 1 << std::endl << std::flush; + std::cout << "\rprocess frame " << (int)frame - 1 << std::flush; - // convert - - outputStreamAudio.encodeFrame( audioFrame, codedFrame ); + audioTransform.convert( audioFrameSource, audioFrameToEncode ); + outputStreamAudio.encodeFrame( audioFrameToEncode, codedFrame ); + outputFile.wrap( codedFrame, 0 ); ++frame; +// if(frame == 10*48100) +// break; } std::cout << std::endl; outputStreamAudio.encodeFrame( codedFrame ); - + outputFile.wrap( codedFrame, 0 ); + + // end of transcoding process + outputFile.endWrap(); } diff --git a/src/AvTranscoder/AudioTransform.cpp b/src/AvTranscoder/AudioTransform.cpp new file mode 100644 index 00000000..8faf9031 --- /dev/null +++ b/src/AvTranscoder/AudioTransform.cpp @@ -0,0 +1,74 @@ +#include "AudioTransform.hpp" +#include "DatasStructures/AudioFrame.hpp" +#include "common.hpp" + +extern "C" { +#ifndef __STDC_CONSTANT_MACROS + #define __STDC_CONSTANT_MACROS +#endif +#include +#include +#include +#if LIBAVCODEC_VERSION_MAJOR > 54 + #include +#endif +} + +#include + +namespace avtranscoder +{ + +AudioTransform::AudioTransform() + : m_audioConvertContext( NULL ) + , m_isInit ( false ) +{ +} + +bool AudioTransform::init( const AudioFrame& src, const AudioFrame& dst ) +{ + m_audioConvertContext = swr_alloc(); + + if( !m_audioConvertContext ) + { + throw std::runtime_error( "unable to create audio convert context" ); + } + + av_opt_set_int(m_audioConvertContext, "in_channel_layout", av_get_default_channel_layout( src.desc().getChannels() ), 0); + av_opt_set_int(m_audioConvertContext, "out_channel_layout", av_get_default_channel_layout( dst.desc().getChannels() ), 0); + + av_opt_set_int(m_audioConvertContext, "in_sample_rate", src.desc().getSampleRate(), 0); + av_opt_set_int(m_audioConvertContext, "out_sample_rate", dst.desc().getSampleRate(), 0); + + av_opt_set_int(m_audioConvertContext, "in_sample_fmt", src.desc().getSampleFormat(), 0); + av_opt_set_int(m_audioConvertContext, "out_sample_fmt", dst.desc().getSampleFormat(), 0); + + if( swr_init( m_audioConvertContext ) < 0 ) + { + swr_free( &m_audioConvertContext ); + throw std::runtime_error( "unable to open audio convert context" ); + } + + return true; +} + +void AudioTransform::convert( const AudioFrame& src, AudioFrame& dst ) +{ + if( ! m_isInit ) + { + m_isInit = init( src, dst ); + m_isInit = true; + } + + if( dst.getSize() != src.getSize() ) + dst.getBuffer().resize( src.getSize(), 0 ); + + const unsigned char* srcData = src.getPtr(); + unsigned char* dstData = dst.getPtr(); + + swr_convert( m_audioConvertContext, &dstData, dst.getSize(), &srcData, src.getSize() ); + + dst.setNbSamples( src.getNbSamples() ); +} + +} diff --git a/src/AvTranscoder/AudioTransform.hpp b/src/AvTranscoder/AudioTransform.hpp new file mode 100644 index 00000000..543fe7f9 --- /dev/null +++ b/src/AvTranscoder/AudioTransform.hpp @@ -0,0 +1,30 @@ +#ifndef _AV_TRANSCODER_AUDIO_TRANSFORM_HPP +#define _AV_TRANSCODER_AUDIO_TRANSFORM_HPP + +#include "common.hpp" + +class SwrContext; + +namespace avtranscoder +{ + +class AudioFrame; + +class AvExport AudioTransform +{ +public: + AudioTransform(); + + void convert( const AudioFrame& src, AudioFrame& dst ); + +private: + bool init( const AudioFrame& src, const AudioFrame& dst ); + + SwrContext* m_audioConvertContext; + + bool m_isInit; +}; + +} + +#endif diff --git a/src/AvTranscoder/DatasStructures/AudioDesc.cpp b/src/AvTranscoder/DatasStructures/AudioDesc.cpp index 59199ea5..02207ed6 100644 --- a/src/AvTranscoder/DatasStructures/AudioDesc.cpp +++ b/src/AvTranscoder/DatasStructures/AudioDesc.cpp @@ -1,4 +1,5 @@ #include "AudioDesc.hpp" +#include "AudioFrame.hpp" extern "C" { #ifndef __STDC_CONSTANT_MACROS @@ -209,5 +210,16 @@ const AVSampleFormat AudioDesc::getSampleFormat() const return m_codecContext->sample_fmt; } +AudioFrameDesc AudioDesc::getFrameDesc() const +{ + AudioFrameDesc audioFrameDesc; + + audioFrameDesc.setChannels( m_codecContext->channels ); + audioFrameDesc.setSampleRate( m_codecContext->sample_rate ); + audioFrameDesc.setSampleFormat( m_codecContext->sample_fmt ); + + return audioFrameDesc; +} + } diff --git a/src/AvTranscoder/DatasStructures/AudioDesc.hpp b/src/AvTranscoder/DatasStructures/AudioDesc.hpp index d06f25cc..f3eb6904 100644 --- a/src/AvTranscoder/DatasStructures/AudioDesc.hpp +++ b/src/AvTranscoder/DatasStructures/AudioDesc.hpp @@ -18,6 +18,8 @@ extern "C" { namespace avtranscoder { +class AudioFrameDesc; + class AvExport AudioDesc { public: @@ -48,6 +50,8 @@ class AvExport AudioDesc AVCodecContext* getCodecContext() const { return m_codecContext; } #endif + AudioFrameDesc getFrameDesc() const; + private: void initCodecContext( ); From e21acb72e3cdfe938269fda5663c4065271f1fc9 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Thu, 5 Jun 2014 12:12:51 +0200 Subject: [PATCH 2/5] InputStreamAudio: suppress tmp variable --- src/AvTranscoder/InputStreamAudio.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/AvTranscoder/InputStreamAudio.cpp b/src/AvTranscoder/InputStreamAudio.cpp index c65b14b5..f9a1889e 100644 --- a/src/AvTranscoder/InputStreamAudio.cpp +++ b/src/AvTranscoder/InputStreamAudio.cpp @@ -140,10 +140,9 @@ bool InputStreamAudio::readNextFrame( AudioFrame& audioFrameBuffer ) if( audioFrameBuffer.getSize() != decodedSize ) audioFrameBuffer.getBuffer().resize( decodedSize, 0 ); - unsigned char* dest = audioFrameBuffer.getPtr(); - int nb_channels = m_codecContext->channels; - av_samples_copy(&dest, (uint8_t* const* )m_frame->data, 0, - 0, m_frame->nb_samples, nb_channels, + unsigned char* dst = audioFrameBuffer.getPtr(); + av_samples_copy(&dst, (uint8_t* const* )m_frame->data, 0, + 0, m_frame->nb_samples, m_codecContext->channels, m_codecContext->sample_fmt); } From f085e6e8c1566431c5690fc25b8965d01be57865 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Thu, 5 Jun 2014 12:15:04 +0200 Subject: [PATCH 3/5] AudioDesc: include AudioFrame instead of forward declaration AudioFrameDesc can be used in the public API. --- src/AvTranscoder/DatasStructures/AudioDesc.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AvTranscoder/DatasStructures/AudioDesc.hpp b/src/AvTranscoder/DatasStructures/AudioDesc.hpp index f3eb6904..9b2132d6 100644 --- a/src/AvTranscoder/DatasStructures/AudioDesc.hpp +++ b/src/AvTranscoder/DatasStructures/AudioDesc.hpp @@ -15,11 +15,11 @@ extern "C" { #include } +#include + namespace avtranscoder { -class AudioFrameDesc; - class AvExport AudioDesc { public: From 6f68e2f798781f398448c2f3a6edeb28d9f429da Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Thu, 5 Jun 2014 12:19:05 +0200 Subject: [PATCH 4/5] AudioTransform: set options in a simpler way Use swr_alloc_set_opts() instead of setting options one by one, with a risk of runtime error if an option we want to set doesn't exist. --- src/AvTranscoder/AudioTransform.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/AvTranscoder/AudioTransform.cpp b/src/AvTranscoder/AudioTransform.cpp index 8faf9031..ca4fdca0 100644 --- a/src/AvTranscoder/AudioTransform.cpp +++ b/src/AvTranscoder/AudioTransform.cpp @@ -34,14 +34,10 @@ bool AudioTransform::init( const AudioFrame& src, const AudioFrame& dst ) throw std::runtime_error( "unable to create audio convert context" ); } - av_opt_set_int(m_audioConvertContext, "in_channel_layout", av_get_default_channel_layout( src.desc().getChannels() ), 0); - av_opt_set_int(m_audioConvertContext, "out_channel_layout", av_get_default_channel_layout( dst.desc().getChannels() ), 0); - - av_opt_set_int(m_audioConvertContext, "in_sample_rate", src.desc().getSampleRate(), 0); - av_opt_set_int(m_audioConvertContext, "out_sample_rate", dst.desc().getSampleRate(), 0); - - av_opt_set_int(m_audioConvertContext, "in_sample_fmt", src.desc().getSampleFormat(), 0); - av_opt_set_int(m_audioConvertContext, "out_sample_fmt", dst.desc().getSampleFormat(), 0); + swr_alloc_set_opts( m_audioConvertContext, + av_get_default_channel_layout( dst.desc().getChannels() ), dst.desc().getSampleFormat(), av_get_default_channel_layout( dst.desc().getSampleRate() ), + av_get_default_channel_layout( src.desc().getChannels() ), src.desc().getSampleFormat(), av_get_default_channel_layout( src.desc().getSampleRate() ), + 0, NULL); if( swr_init( m_audioConvertContext ) < 0 ) { From 887df9cfe92d68c714f2ab8029cddb9423f14ff2 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Thu, 5 Jun 2014 12:20:52 +0200 Subject: [PATCH 5/5] AudioRewrapper: refactoring * Rename audioODesc to audioOutputDesc. * Explain the magick numbers ;) --- app/audioRewrapper/audioRewrapper.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/audioRewrapper/audioRewrapper.cpp b/app/audioRewrapper/audioRewrapper.cpp index e886347c..57f18b5a 100644 --- a/app/audioRewrapper/audioRewrapper.cpp +++ b/app/audioRewrapper/audioRewrapper.cpp @@ -65,9 +65,9 @@ void transcodeAudio( const char* inputfilename, const char* outputFilename ) // init audio encoders OutputStreamAudio outputStreamAudio; - AudioDesc& audioDesc = outputStreamAudio.getAudioDesc(); - audioDesc.setAudioCodec( "pcm_s24le" ); - audioDesc.setAudioParameters( + AudioDesc& audioOutputDesc = outputStreamAudio.getAudioDesc(); + audioOutputDesc.setAudioCodec( "pcm_s24le" ); + audioOutputDesc.setAudioParameters( inputFile.getStream( 0 ).getAudioDesc().getSampleRate(), inputFile.getStream( 0 ).getAudioDesc().getChannels(), AV_SAMPLE_FMT_S32//,inputFile.getStream( 0 ).getAudioDesc().getSampleFormat() @@ -79,7 +79,7 @@ void transcodeAudio( const char* inputfilename, const char* outputFilename ) exit( -1 ); } - outputFile.addAudioStream( audioDesc ); + outputFile.addAudioStream( audioOutputDesc ); outputFile.beginWrap(); // init convert @@ -91,7 +91,7 @@ void transcodeAudio( const char* inputfilename, const char* outputFilename ) std::cout << "start transcoding" << std::endl; AudioFrame audioFrameSource( inputFile.getStream( 0 ).getAudioDesc().getFrameDesc() ); - AudioFrame audioFrameToEncode( audioDesc.getFrameDesc() ); + AudioFrame audioFrameToEncode( audioOutputDesc.getFrameDesc() ); size_t frame = 0; while( inputStreamAudio.readNextFrame( audioFrameSource ) ) @@ -105,6 +105,7 @@ void transcodeAudio( const char* inputfilename, const char* outputFilename ) outputFile.wrap( codedFrame, 0 ); ++frame; + // if you want to stop the transcoding process (after 10s at 48,1 KHz) // if(frame == 10*48100) // break; }