From 3accac45783f10a865705cc682d38f667233931d Mon Sep 17 00:00:00 2001 From: Marten Richter Date: Sun, 3 Mar 2013 18:41:19 +0100 Subject: [PATCH] Add downmixing code for codecs of libav with no downmix support --- audioomx.cc | 139 +++++++++++++++++++++++++++++++++++++++++++++++++--- audioomx.h | 10 ++++ 2 files changed, 141 insertions(+), 8 deletions(-) diff --git a/audioomx.cc b/audioomx.cc index d554ca2..b37279d 100644 --- a/audioomx.cc +++ b/audioomx.cc @@ -57,6 +57,9 @@ AudioOMX::AudioOMX() mp23codec_libav=NULL; mp23codec_context_libav=NULL; +#ifdef USE_LIBRESAMPLE + resam_con_libav=NULL; +#endif decompress_buffer=NULL; decompress_buffer_size=0; @@ -841,6 +844,22 @@ int AudioOMX::InitDecoderLibAV() libav_mutex.Unlock(); return 0; } +#ifdef USE_LIBRESAMPLE + resam_con_libav = avresample_alloc_context(); + if (resam_con_libav == NULL) { + Log::getInstance()->log("Audio", Log::DEBUG, + "Alloc resample context failed"); + return 0; + } + + av_opt_set_int(resam_con_libav, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0); // our standard format + av_opt_set_int(resam_con_libav, "out_sample_rate",48000,0); + av_opt_set_int(resam_con_libav, "out_sample_fmt",AV_SAMPLE_FMT_S16,0); + + av_opt_set_int(resam_con_libav, "in_sample_rate",48000,0); + av_opt_set_int(resam_con_libav, "in_sample_fmt",AV_SAMPLE_FMT_S16,0); + av_opt_set_int(resam_con_libav, "in_channel_layout", AV_CH_LAYOUT_5POINT1, 0); //just an example +#endif av_init_packet(&incoming_paket_libav); decode_frame_libav=avcodec_alloc_frame(); @@ -870,6 +889,10 @@ void AudioOMX::DeinitDecoderLibAV() { avcodec_close(mp23codec_context_libav); av_free(mp23codec_context_libav); mp23codec_context_libav = NULL; +#ifdef USE_LIBRESAMPLE + avresample_free(resam_con_libav); + resam_con_libav=NULL; +#endif } libav_mutex.Unlock(); @@ -1590,7 +1613,51 @@ unsigned int AudioOMX::AdvanceAacLatmAudioSync(const UCHAR *data,unsigned int si } return size; } +#ifndef USE_LIBRESAMPLE +#define SQRT3_2 1.22474487139158904909 +void AudioOMX::getDownMixMatrix(unsigned long long channels, + double *left_mat,double *right_mat) +{ + int i,j; + double downmix_matrix[2][64]; + for (i=0;i<64;i++) { + for (j=0;j<2;j++) { + downmix_matrix[j][i]=0.; + } + } + downmix_matrix[0/*links*/][/*FRONT_LEFT*/0]=1.; + downmix_matrix[1/*rechts*/][/*FRONT_RIGHT*/1]=1.; + if (channels & (AV_CH_BACK_LEFT | AV_CH_SIDE_LEFT) ) { + downmix_matrix[0/*links*/][/*BACK_CENTER*/8]=-M_SQRT1_2*M_SQRT1_2; + downmix_matrix[1/*rechts*/][/*BACK_CENTER*/8]=M_SQRT1_2*M_SQRT1_2; + } else { + downmix_matrix[0/*links*/][/*BACK_CENTER*/8]=-M_SQRT1_2; + downmix_matrix[1/*rechts*/][/*BACK_CENTER*/8]=M_SQRT1_2; + } + downmix_matrix[0/*links*/][/*BACK_LEFT*/4 ]=-M_SQRT1_2*SQRT3_2; + downmix_matrix[1/*rechts*/][/*BACK_LEFT*/4]=M_SQRT1_2*M_SQRT1_2; + downmix_matrix[0/*links*/][/*BACK_RIGHT*/5 ]=-M_SQRT1_2*M_SQRT1_2; + downmix_matrix[1/*rechts*/][/*BACK_RIGHT*/5]=M_SQRT1_2*SQRT3_2; + downmix_matrix[0/*links*/][/*SIDE_LEFT*/9 ]=-M_SQRT1_2*SQRT3_2; + downmix_matrix[1/*rechts*/][/*SIDE_LEFT*/9]=M_SQRT1_2*M_SQRT1_2; + downmix_matrix[0/*links*/][/*SIDE_RIGHT*/10 ]=-M_SQRT1_2*M_SQRT1_2; + downmix_matrix[1/*rechts*/][/*SIDE_RIGHT*/10]=M_SQRT1_2*SQRT3_2; + downmix_matrix[0/*links*/][/*FRONT_LEFT_OF_CENTER*/6]=1.; + downmix_matrix[1/*rechts*/][/*FRONT_RIGHT_OF_CENTER*/7]=1.; + downmix_matrix[0/*links*/][/*LOW_FREQUENCY*/3]=M_SQRT1_2; + downmix_matrix[1/*rechts*/][/*LOW_FREQUENCY*/3]=M_SQRT1_2; + + for (i=0,j=0;i<64;i++) { + if ((1ULL << i)& channels) { + left_mat[j]=downmix_matrix[0][i]; + right_mat[j]=downmix_matrix[1][i]; + j++; + } + } +} + +#endif void AudioOMX::PrepareMediaSample(const MediaPacketList& mplist,UINT samplepos) { @@ -2034,10 +2101,14 @@ UINT AudioOMX::DeliverMediaPacket(MediaPacket packet, const UCHAR* buffer, if (gotta) { //Log::getInstance()->log("Audio", Log::DEBUG, // "Got a frame"); + int dsize = av_samples_get_buffer_size(NULL, - current_context->channels, decode_frame_libav->nb_samples, + /*current_context->channels*/2, decode_frame_libav->nb_samples, current_context->sample_fmt, 1); - if (current_context->channels==1) dsize*=2; // we convert mono to stereo + int dsize_in = av_samples_get_buffer_size(NULL, + current_context->channels, decode_frame_libav->nb_samples, + current_context->sample_fmt, 1); + //if (current_context->channels==1) dsize*=2; // we convert mono to stereo if ((cur_input_buf_omx->nFilledLen + dsize) > cur_input_buf_omx->nAllocLen ) { // I doubt that this will ever happen @@ -2081,22 +2152,74 @@ UINT AudioOMX::DeliverMediaPacket(MediaPacket packet, const UCHAR* buffer, } //Log::getInstance()->log("Audio", Log::DEBUG,"memcpy in %d %d %d" ,dsize,current_context->sample_rate,cur_input_buf_omx->nFilledLen); - if (current_context->channels!=1) { + if (current_context->channels==2) { memcpy(cur_input_buf_omx->pBuffer + cur_input_buf_omx->nFilledLen, decode_frame_libav->data[0], dsize); - } else { //convert to stereo - unsigned short* startbuffer=(unsigned short* )decode_frame_libav->data[0]; - unsigned short* endbuffer=(unsigned short* )(decode_frame_libav->data[0]+dsize/2); - unsigned short* destbuffer=(unsigned short* )(cur_input_buf_omx->pBuffer + cur_input_buf_omx->nFilledLen); + } +#ifndef USE_LIBRESAMPLE + else if (current_context->channels==1) { //convert to stereo + short* startbuffer=(short* )decode_frame_libav->data[0]; + short* endbuffer=(short* )(decode_frame_libav->data[0]+dsize/2); + short* destbuffer=(short* )(cur_input_buf_omx->pBuffer + cur_input_buf_omx->nFilledLen); while (startbuffer!=endbuffer) { - unsigned short temp=*startbuffer; + unsigned short temp=*startbuffer; *destbuffer=temp; destbuffer++; *destbuffer=temp; destbuffer++; startbuffer++; } + } else { + unsigned int channels=current_context->channels; + double left_mat[channels]; + double right_mat[channels]; + getDownMixMatrix(current_context->channel_layout,left_mat,right_mat); + + short* startbuffer=(short* )decode_frame_libav->data[0]; + short* endbuffer=(short* )(decode_frame_libav->data[0]+dsize_in); + short* destbuffer=(short* )(cur_input_buf_omx->pBuffer + cur_input_buf_omx->nFilledLen); + while (startbuffer!=endbuffer) { + short* cur_buf=startbuffer; + short* cur_buf_end=startbuffer+channels; + double work1=0.; + double work2=0.; + double *mat1=left_mat; + double *mat2=right_mat; + while (cur_buf!=cur_buf_end) { + work1+= ((*mat1)*((double)*cur_buf)); + work2+= ((*mat2)*((double)*cur_buf)); + cur_buf++; + mat1++; + mat2++; + } + *destbuffer=work1; + destbuffer++; + *destbuffer=work2; + destbuffer++; + startbuffer+=channels; + + } + } +#else + else { + //untested for future use + av_opt_set_int(resam_con_libav, "in_sample_rate",current_context->sample_rate,0); + av_opt_set_int(resam_con_libav, "in_sample_fmt",current_context->sample_fmt,0); + av_opt_set_int(resam_con_libav, "in_channel_layout",current_context->channel_layout, 0); + int ret=avresample_open(resam_con_libav); + if (ret<0) { + Log::getInstance()->log("Audio", Log::ERR,"Opening AV resample failed %d",ret); + } else { + avresample_convert(resam_con_libav, cur_input_buf_omx->pBuffer + cur_input_buf_omx->nFilledLen, + dsize, decode_frame_libav->nb_samples, + decode_frame_libav->data[0], dsize_in, decode_frame_libav->nb_samples); + avresample_close(resam_con_libav); + } + + } +#endif + //Log::getInstance()->log("Audio", Log::DEBUG,"memcpy out"); cur_input_buf_omx->nFilledLen += dsize; } else { diff --git a/audioomx.h b/audioomx.h index ddbc9d3..9e49b65 100644 --- a/audioomx.h +++ b/audioomx.h @@ -30,9 +30,14 @@ #include "audio.h" #include "videoomx.h" +//#define USE_LIBRESAMPLE // untested code for future use + extern "C" { #include #include +#ifdef USE_LIBRESAMPLE +#include +#endif } @@ -181,6 +186,11 @@ class AudioOMX : public Audio AVCodecContext *mp23codec_context_libav; AVPacket incoming_paket_libav; AVFrame *decode_frame_libav; +#ifdef USE_LIBRESAMPLE + AVAudioResampleContext *resam_con_libav; +#else + void getDownMixMatrix(unsigned long long channels,double *left_mat,double *right_mat); +#endif UCHAR * decompress_buffer; unsigned int decompress_buffer_size; -- 2.39.2