]> git.vomp.tv Git - vompclient.git/commitdiff
Add downmixing code for codecs of libav with no downmix support
authorMarten Richter <marten.richter@freenet.de>
Sun, 3 Mar 2013 17:41:19 +0000 (18:41 +0100)
committerMarten Richter <marten.richter@freenet.de>
Sun, 3 Mar 2013 17:41:19 +0000 (18:41 +0100)
audioomx.cc
audioomx.h

index d554ca2d42e1e4bd27b6cd88ee963416aa8732e7..b37279d8efc093e80f6326ece91185644c6530d9 100644 (file)
@@ -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 {
index ddbc9d32fa78923c787ff9914145328aa75e91e0..9e49b65313f780765e45f7a2d75b527aeba4a97a 100644 (file)
 #include "audio.h"
 #include "videoomx.h"
 
+//#define USE_LIBRESAMPLE // untested code for future use
+
 extern "C" {
 #include <libavcodec/avcodec.h>
 #include <libavformat/avformat.h>
+#ifdef USE_LIBRESAMPLE
+#include <libavresample/avresample.h>
+#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;