LCOV - code coverage report
Current view: top level - src/libavresample - audio_mix.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 3 366 0.8 %
Date: 2017-01-28 02:43:52 Functions: 1 18 5.6 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
       3             :  *
       4             :  * This file is part of FFmpeg.
       5             :  *
       6             :  * FFmpeg is free software; you can redistribute it and/or
       7             :  * modify it under the terms of the GNU Lesser General Public
       8             :  * License as published by the Free Software Foundation; either
       9             :  * version 2.1 of the License, or (at your option) any later version.
      10             :  *
      11             :  * FFmpeg is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :  * Lesser General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU Lesser General Public
      17             :  * License along with FFmpeg; if not, write to the Free Software
      18             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      19             :  */
      20             : 
      21             : #include <stdint.h>
      22             : 
      23             : #include "libavutil/common.h"
      24             : #include "libavutil/libm.h"
      25             : #include "libavutil/samplefmt.h"
      26             : #include "avresample.h"
      27             : #include "internal.h"
      28             : #include "audio_data.h"
      29             : #include "audio_mix.h"
      30             : 
      31             : static const char * const coeff_type_names[] = { "q8", "q15", "flt" };
      32             : 
      33             : struct AudioMix {
      34             :     AVAudioResampleContext *avr;
      35             :     enum AVSampleFormat fmt;
      36             :     enum AVMixCoeffType coeff_type;
      37             :     uint64_t in_layout;
      38             :     uint64_t out_layout;
      39             :     int in_channels;
      40             :     int out_channels;
      41             : 
      42             :     int ptr_align;
      43             :     int samples_align;
      44             :     int has_optimized_func;
      45             :     const char *func_descr;
      46             :     const char *func_descr_generic;
      47             :     mix_func *mix;
      48             :     mix_func *mix_generic;
      49             : 
      50             :     int in_matrix_channels;
      51             :     int out_matrix_channels;
      52             :     int output_zero[AVRESAMPLE_MAX_CHANNELS];
      53             :     int input_skip[AVRESAMPLE_MAX_CHANNELS];
      54             :     int output_skip[AVRESAMPLE_MAX_CHANNELS];
      55             :     int16_t *matrix_q8[AVRESAMPLE_MAX_CHANNELS];
      56             :     int32_t *matrix_q15[AVRESAMPLE_MAX_CHANNELS];
      57             :     float   *matrix_flt[AVRESAMPLE_MAX_CHANNELS];
      58             :     void   **matrix;
      59             : };
      60             : 
      61           0 : void ff_audio_mix_set_func(AudioMix *am, enum AVSampleFormat fmt,
      62             :                            enum AVMixCoeffType coeff_type, int in_channels,
      63             :                            int out_channels, int ptr_align, int samples_align,
      64             :                            const char *descr, void *mix_func)
      65             : {
      66           0 :     if (fmt == am->fmt && coeff_type == am->coeff_type &&
      67           0 :         ( in_channels ==  am->in_matrix_channels ||  in_channels == 0) &&
      68           0 :         (out_channels == am->out_matrix_channels || out_channels == 0)) {
      69             :         char chan_str[16];
      70           0 :         am->mix           = mix_func;
      71           0 :         am->func_descr    = descr;
      72           0 :         am->ptr_align     = ptr_align;
      73           0 :         am->samples_align = samples_align;
      74           0 :         if (ptr_align == 1 && samples_align == 1) {
      75           0 :             am->mix_generic        = mix_func;
      76           0 :             am->func_descr_generic = descr;
      77             :         } else {
      78           0 :             am->has_optimized_func = 1;
      79             :         }
      80           0 :         if (in_channels) {
      81           0 :             if (out_channels)
      82           0 :                 snprintf(chan_str, sizeof(chan_str), "[%d to %d] ",
      83             :                          in_channels, out_channels);
      84             :             else
      85           0 :                 snprintf(chan_str, sizeof(chan_str), "[%d to any] ",
      86             :                          in_channels);
      87           0 :         } else if (out_channels) {
      88           0 :                 snprintf(chan_str, sizeof(chan_str), "[any to %d] ",
      89             :                          out_channels);
      90             :         } else {
      91           0 :             snprintf(chan_str, sizeof(chan_str), "[any to any] ");
      92             :         }
      93           0 :         av_log(am->avr, AV_LOG_DEBUG, "audio_mix: found function: [fmt=%s] "
      94             :                "[c=%s] %s(%s)\n", av_get_sample_fmt_name(fmt),
      95             :                coeff_type_names[coeff_type], chan_str, descr);
      96             :     }
      97           0 : }
      98             : 
      99             : #define MIX_FUNC_NAME(fmt, cfmt) mix_any_ ## fmt ##_## cfmt ##_c
     100             : 
     101             : #define MIX_FUNC_GENERIC(fmt, cfmt, stype, ctype, sumtype, expr)            \
     102             : static void MIX_FUNC_NAME(fmt, cfmt)(stype **samples, ctype **matrix,       \
     103             :                                      int len, int out_ch, int in_ch)        \
     104             : {                                                                           \
     105             :     int i, in, out;                                                         \
     106             :     stype temp[AVRESAMPLE_MAX_CHANNELS];                                    \
     107             :     for (i = 0; i < len; i++) {                                             \
     108             :         for (out = 0; out < out_ch; out++) {                                \
     109             :             sumtype sum = 0;                                                \
     110             :             for (in = 0; in < in_ch; in++)                                  \
     111             :                 sum += samples[in][i] * matrix[out][in];                    \
     112             :             temp[out] = expr;                                               \
     113             :         }                                                                   \
     114             :         for (out = 0; out < out_ch; out++)                                  \
     115             :             samples[out][i] = temp[out];                                    \
     116             :     }                                                                       \
     117             : }
     118             : 
     119           0 : MIX_FUNC_GENERIC(FLTP, FLT, float,   float,   float,   sum)
     120           0 : MIX_FUNC_GENERIC(S16P, FLT, int16_t, float,   float,   av_clip_int16(lrintf(sum)))
     121           0 : MIX_FUNC_GENERIC(S16P, Q15, int16_t, int32_t, int64_t, av_clip_int16(sum >> 15))
     122           0 : MIX_FUNC_GENERIC(S16P, Q8,  int16_t, int16_t, int32_t, av_clip_int16(sum >>  8))
     123             : 
     124             : /* TODO: templatize the channel-specific C functions */
     125             : 
     126           0 : static void mix_2_to_1_fltp_flt_c(float **samples, float **matrix, int len,
     127             :                                   int out_ch, int in_ch)
     128             : {
     129           0 :     float *src0 = samples[0];
     130           0 :     float *src1 = samples[1];
     131           0 :     float *dst  = src0;
     132           0 :     float m0    = matrix[0][0];
     133           0 :     float m1    = matrix[0][1];
     134             : 
     135           0 :     while (len > 4) {
     136           0 :         *dst++ = *src0++ * m0 + *src1++ * m1;
     137           0 :         *dst++ = *src0++ * m0 + *src1++ * m1;
     138           0 :         *dst++ = *src0++ * m0 + *src1++ * m1;
     139           0 :         *dst++ = *src0++ * m0 + *src1++ * m1;
     140           0 :         len -= 4;
     141             :     }
     142           0 :     while (len > 0) {
     143           0 :         *dst++ = *src0++ * m0 + *src1++ * m1;
     144           0 :         len--;
     145             :     }
     146           0 : }
     147             : 
     148           0 : static void mix_2_to_1_s16p_flt_c(int16_t **samples, float **matrix, int len,
     149             :                                   int out_ch, int in_ch)
     150             : {
     151           0 :     int16_t *src0 = samples[0];
     152           0 :     int16_t *src1 = samples[1];
     153           0 :     int16_t *dst  = src0;
     154           0 :     float m0      = matrix[0][0];
     155           0 :     float m1      = matrix[0][1];
     156             : 
     157           0 :     while (len > 4) {
     158           0 :         *dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1));
     159           0 :         *dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1));
     160           0 :         *dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1));
     161           0 :         *dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1));
     162           0 :         len -= 4;
     163             :     }
     164           0 :     while (len > 0) {
     165           0 :         *dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1));
     166           0 :         len--;
     167             :     }
     168           0 : }
     169             : 
     170           0 : static void mix_2_to_1_s16p_q8_c(int16_t **samples, int16_t **matrix, int len,
     171             :                                  int out_ch, int in_ch)
     172             : {
     173           0 :     int16_t *src0 = samples[0];
     174           0 :     int16_t *src1 = samples[1];
     175           0 :     int16_t *dst  = src0;
     176           0 :     int16_t m0    = matrix[0][0];
     177           0 :     int16_t m1    = matrix[0][1];
     178             : 
     179           0 :     while (len > 4) {
     180           0 :         *dst++ = (*src0++ * m0 + *src1++ * m1) >> 8;
     181           0 :         *dst++ = (*src0++ * m0 + *src1++ * m1) >> 8;
     182           0 :         *dst++ = (*src0++ * m0 + *src1++ * m1) >> 8;
     183           0 :         *dst++ = (*src0++ * m0 + *src1++ * m1) >> 8;
     184           0 :         len -= 4;
     185             :     }
     186           0 :     while (len > 0) {
     187           0 :         *dst++ = (*src0++ * m0 + *src1++ * m1) >> 8;
     188           0 :         len--;
     189             :     }
     190           0 : }
     191             : 
     192           0 : static void mix_1_to_2_fltp_flt_c(float **samples, float **matrix, int len,
     193             :                                   int out_ch, int in_ch)
     194             : {
     195             :     float v;
     196           0 :     float *dst0 = samples[0];
     197           0 :     float *dst1 = samples[1];
     198           0 :     float *src  = dst0;
     199           0 :     float m0    = matrix[0][0];
     200           0 :     float m1    = matrix[1][0];
     201             : 
     202           0 :     while (len > 4) {
     203           0 :         v = *src++;
     204           0 :         *dst0++ = v * m0;
     205           0 :         *dst1++ = v * m1;
     206           0 :         v = *src++;
     207           0 :         *dst0++ = v * m0;
     208           0 :         *dst1++ = v * m1;
     209           0 :         v = *src++;
     210           0 :         *dst0++ = v * m0;
     211           0 :         *dst1++ = v * m1;
     212           0 :         v = *src++;
     213           0 :         *dst0++ = v * m0;
     214           0 :         *dst1++ = v * m1;
     215           0 :         len -= 4;
     216             :     }
     217           0 :     while (len > 0) {
     218           0 :         v = *src++;
     219           0 :         *dst0++ = v * m0;
     220           0 :         *dst1++ = v * m1;
     221           0 :         len--;
     222             :     }
     223           0 : }
     224             : 
     225           0 : static void mix_6_to_2_fltp_flt_c(float **samples, float **matrix, int len,
     226             :                                   int out_ch, int in_ch)
     227             : {
     228             :     float v0, v1;
     229           0 :     float *src0 = samples[0];
     230           0 :     float *src1 = samples[1];
     231           0 :     float *src2 = samples[2];
     232           0 :     float *src3 = samples[3];
     233           0 :     float *src4 = samples[4];
     234           0 :     float *src5 = samples[5];
     235           0 :     float *dst0 = src0;
     236           0 :     float *dst1 = src1;
     237           0 :     float *m0   = matrix[0];
     238           0 :     float *m1   = matrix[1];
     239             : 
     240           0 :     while (len > 0) {
     241           0 :         v0 = *src0++;
     242           0 :         v1 = *src1++;
     243           0 :         *dst0++ = v0      * m0[0] +
     244           0 :                   v1      * m0[1] +
     245           0 :                   *src2   * m0[2] +
     246           0 :                   *src3   * m0[3] +
     247           0 :                   *src4   * m0[4] +
     248           0 :                   *src5   * m0[5];
     249           0 :         *dst1++ = v0      * m1[0] +
     250           0 :                   v1      * m1[1] +
     251           0 :                   *src2++ * m1[2] +
     252           0 :                   *src3++ * m1[3] +
     253           0 :                   *src4++ * m1[4] +
     254           0 :                   *src5++ * m1[5];
     255           0 :         len--;
     256             :     }
     257           0 : }
     258             : 
     259           0 : static void mix_2_to_6_fltp_flt_c(float **samples, float **matrix, int len,
     260             :                                   int out_ch, int in_ch)
     261             : {
     262             :     float v0, v1;
     263           0 :     float *dst0 = samples[0];
     264           0 :     float *dst1 = samples[1];
     265           0 :     float *dst2 = samples[2];
     266           0 :     float *dst3 = samples[3];
     267           0 :     float *dst4 = samples[4];
     268           0 :     float *dst5 = samples[5];
     269           0 :     float *src0 = dst0;
     270           0 :     float *src1 = dst1;
     271             : 
     272           0 :     while (len > 0) {
     273           0 :         v0 = *src0++;
     274           0 :         v1 = *src1++;
     275           0 :         *dst0++ = v0 * matrix[0][0] + v1 * matrix[0][1];
     276           0 :         *dst1++ = v0 * matrix[1][0] + v1 * matrix[1][1];
     277           0 :         *dst2++ = v0 * matrix[2][0] + v1 * matrix[2][1];
     278           0 :         *dst3++ = v0 * matrix[3][0] + v1 * matrix[3][1];
     279           0 :         *dst4++ = v0 * matrix[4][0] + v1 * matrix[4][1];
     280           0 :         *dst5++ = v0 * matrix[5][0] + v1 * matrix[5][1];
     281           0 :         len--;
     282             :     }
     283           0 : }
     284             : 
     285           0 : static av_cold int mix_function_init(AudioMix *am)
     286             : {
     287           0 :     am->func_descr = am->func_descr_generic = "n/a";
     288           0 :     am->mix = am->mix_generic = NULL;
     289             : 
     290             :     /* no need to set a mix function when we're skipping mixing */
     291           0 :     if (!am->in_matrix_channels || !am->out_matrix_channels)
     292           0 :         return 0;
     293             : 
     294             :     /* any-to-any C versions */
     295             : 
     296           0 :     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,
     297             :                           0, 0, 1, 1, "C", MIX_FUNC_NAME(FLTP, FLT));
     298             : 
     299           0 :     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,
     300             :                           0, 0, 1, 1, "C", MIX_FUNC_NAME(S16P, FLT));
     301             : 
     302           0 :     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_Q15,
     303             :                           0, 0, 1, 1, "C", MIX_FUNC_NAME(S16P, Q15));
     304             : 
     305           0 :     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_Q8,
     306             :                           0, 0, 1, 1, "C", MIX_FUNC_NAME(S16P, Q8));
     307             : 
     308             :     /* channel-specific C versions */
     309             : 
     310           0 :     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,
     311             :                           2, 1, 1, 1, "C", mix_2_to_1_fltp_flt_c);
     312             : 
     313           0 :     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,
     314             :                           2, 1, 1, 1, "C", mix_2_to_1_s16p_flt_c);
     315             : 
     316           0 :     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_Q8,
     317             :                           2, 1, 1, 1, "C", mix_2_to_1_s16p_q8_c);
     318             : 
     319           0 :     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,
     320             :                           1, 2, 1, 1, "C", mix_1_to_2_fltp_flt_c);
     321             : 
     322           0 :     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,
     323             :                           6, 2, 1, 1, "C", mix_6_to_2_fltp_flt_c);
     324             : 
     325           0 :     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,
     326             :                           2, 6, 1, 1, "C", mix_2_to_6_fltp_flt_c);
     327             : 
     328             :     if (ARCH_X86)
     329           0 :         ff_audio_mix_init_x86(am);
     330             : 
     331           0 :     if (!am->mix) {
     332           0 :         av_log(am->avr, AV_LOG_ERROR, "audio_mix: NO FUNCTION FOUND: [fmt=%s] "
     333             :                "[c=%s] [%d to %d]\n", av_get_sample_fmt_name(am->fmt),
     334           0 :                coeff_type_names[am->coeff_type], am->in_channels,
     335             :                am->out_channels);
     336           0 :         return AVERROR_PATCHWELCOME;
     337             :     }
     338           0 :     return 0;
     339             : }
     340             : 
     341           0 : AudioMix *ff_audio_mix_alloc(AVAudioResampleContext *avr)
     342             : {
     343             :     AudioMix *am;
     344             :     int ret;
     345             : 
     346           0 :     am = av_mallocz(sizeof(*am));
     347           0 :     if (!am)
     348           0 :         return NULL;
     349           0 :     am->avr = avr;
     350             : 
     351           0 :     if (avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P &&
     352           0 :         avr->internal_sample_fmt != AV_SAMPLE_FMT_FLTP) {
     353           0 :         av_log(avr, AV_LOG_ERROR, "Unsupported internal format for "
     354             :                "mixing: %s\n",
     355             :                av_get_sample_fmt_name(avr->internal_sample_fmt));
     356           0 :         goto error;
     357             :     }
     358             : 
     359           0 :     am->fmt          = avr->internal_sample_fmt;
     360           0 :     am->coeff_type   = avr->mix_coeff_type;
     361           0 :     am->in_layout    = avr->in_channel_layout;
     362           0 :     am->out_layout   = avr->out_channel_layout;
     363           0 :     am->in_channels  = avr->in_channels;
     364           0 :     am->out_channels = avr->out_channels;
     365             : 
     366             :     /* build matrix if the user did not already set one */
     367           0 :     if (avr->mix_matrix) {
     368           0 :         ret = ff_audio_mix_set_matrix(am, avr->mix_matrix, avr->in_channels);
     369           0 :         if (ret < 0)
     370           0 :             goto error;
     371           0 :         av_freep(&avr->mix_matrix);
     372             :     } else {
     373           0 :         double *matrix_dbl = av_mallocz(avr->out_channels * avr->in_channels *
     374             :                                         sizeof(*matrix_dbl));
     375           0 :         if (!matrix_dbl)
     376           0 :             goto error;
     377             : 
     378           0 :         ret = avresample_build_matrix(avr->in_channel_layout,
     379             :                                       avr->out_channel_layout,
     380             :                                       avr->center_mix_level,
     381             :                                       avr->surround_mix_level,
     382             :                                       avr->lfe_mix_level,
     383             :                                       avr->normalize_mix_level,
     384             :                                       matrix_dbl,
     385             :                                       avr->in_channels,
     386             :                                       avr->matrix_encoding);
     387           0 :         if (ret < 0) {
     388           0 :             av_free(matrix_dbl);
     389           0 :             goto error;
     390             :         }
     391             : 
     392           0 :         ret = ff_audio_mix_set_matrix(am, matrix_dbl, avr->in_channels);
     393           0 :         if (ret < 0) {
     394           0 :             av_log(avr, AV_LOG_ERROR, "error setting mix matrix\n");
     395           0 :             av_free(matrix_dbl);
     396           0 :             goto error;
     397             :         }
     398             : 
     399           0 :         av_free(matrix_dbl);
     400             :     }
     401             : 
     402           0 :     return am;
     403             : 
     404             : error:
     405           0 :     av_free(am);
     406           0 :     return NULL;
     407             : }
     408             : 
     409           2 : void ff_audio_mix_free(AudioMix **am_p)
     410             : {
     411             :     AudioMix *am;
     412             : 
     413           2 :     if (!*am_p)
     414           2 :         return;
     415           0 :     am = *am_p;
     416             : 
     417           0 :     if (am->matrix) {
     418           0 :         av_free(am->matrix[0]);
     419           0 :         am->matrix = NULL;
     420             :     }
     421           0 :     memset(am->matrix_q8,  0, sizeof(am->matrix_q8 ));
     422           0 :     memset(am->matrix_q15, 0, sizeof(am->matrix_q15));
     423           0 :     memset(am->matrix_flt, 0, sizeof(am->matrix_flt));
     424             : 
     425           0 :     av_freep(am_p);
     426             : }
     427             : 
     428           0 : int ff_audio_mix(AudioMix *am, AudioData *src)
     429             : {
     430           0 :     int use_generic = 1;
     431           0 :     int len = src->nb_samples;
     432             :     int i, j;
     433             : 
     434             :     /* determine whether to use the optimized function based on pointer and
     435             :        samples alignment in both the input and output */
     436           0 :     if (am->has_optimized_func) {
     437           0 :         int aligned_len = FFALIGN(len, am->samples_align);
     438           0 :         if (!(src->ptr_align % am->ptr_align) &&
     439           0 :             src->samples_align >= aligned_len) {
     440           0 :             len = aligned_len;
     441           0 :             use_generic = 0;
     442             :         }
     443             :     }
     444           0 :     av_log(am->avr, AV_LOG_TRACE, "audio_mix: %d samples - %d to %d channels (%s)\n",
     445             :             src->nb_samples, am->in_channels, am->out_channels,
     446             :             use_generic ? am->func_descr_generic : am->func_descr);
     447             : 
     448           0 :     if (am->in_matrix_channels && am->out_matrix_channels) {
     449             :         uint8_t **data;
     450           0 :         uint8_t *data0[AVRESAMPLE_MAX_CHANNELS] = { NULL };
     451             : 
     452           0 :         if (am->out_matrix_channels < am->out_channels ||
     453           0 :              am->in_matrix_channels <  am->in_channels) {
     454           0 :             for (i = 0, j = 0; i < FFMAX(am->in_channels, am->out_channels); i++) {
     455           0 :                 if (am->input_skip[i] || am->output_skip[i] || am->output_zero[i])
     456           0 :                     continue;
     457           0 :                 data0[j++] = src->data[i];
     458             :             }
     459           0 :             data = data0;
     460             :         } else {
     461           0 :             data = src->data;
     462             :         }
     463             : 
     464           0 :         if (use_generic)
     465           0 :             am->mix_generic(data, am->matrix, len, am->out_matrix_channels,
     466             :                             am->in_matrix_channels);
     467             :         else
     468           0 :             am->mix(data, am->matrix, len, am->out_matrix_channels,
     469             :                     am->in_matrix_channels);
     470             :     }
     471             : 
     472           0 :     if (am->out_matrix_channels < am->out_channels) {
     473           0 :         for (i = 0; i < am->out_channels; i++)
     474           0 :             if (am->output_zero[i])
     475           0 :                 av_samples_set_silence(&src->data[i], 0, len, 1, am->fmt);
     476             :     }
     477             : 
     478           0 :     ff_audio_data_set_channels(src, am->out_channels);
     479             : 
     480           0 :     return 0;
     481             : }
     482             : 
     483           0 : int ff_audio_mix_get_matrix(AudioMix *am, double *matrix, int stride)
     484             : {
     485             :     int i, o, i0, o0;
     486             : 
     487           0 :     if ( am->in_channels <= 0 ||  am->in_channels > AVRESAMPLE_MAX_CHANNELS ||
     488           0 :         am->out_channels <= 0 || am->out_channels > AVRESAMPLE_MAX_CHANNELS) {
     489           0 :         av_log(am->avr, AV_LOG_ERROR, "Invalid channel counts\n");
     490           0 :         return AVERROR(EINVAL);
     491             :     }
     492             : 
     493             : #define GET_MATRIX_CONVERT(suffix, scale)                                   \
     494             :     if (!am->matrix_ ## suffix[0]) {                                        \
     495             :         av_log(am->avr, AV_LOG_ERROR, "matrix is not set\n");               \
     496             :         return AVERROR(EINVAL);                                             \
     497             :     }                                                                       \
     498             :     for (o = 0, o0 = 0; o < am->out_channels; o++) {                        \
     499             :         for (i = 0, i0 = 0; i < am->in_channels; i++) {                     \
     500             :             if (am->input_skip[i] || am->output_zero[o])                    \
     501             :                 matrix[o * stride + i] = 0.0;                               \
     502             :             else                                                            \
     503             :                 matrix[o * stride + i] = am->matrix_ ## suffix[o0][i0] *    \
     504             :                                          (scale);                           \
     505             :             if (!am->input_skip[i])                                         \
     506             :                 i0++;                                                       \
     507             :         }                                                                   \
     508             :         if (!am->output_zero[o])                                            \
     509             :             o0++;                                                           \
     510             :     }
     511             : 
     512           0 :     switch (am->coeff_type) {
     513             :     case AV_MIX_COEFF_TYPE_Q8:
     514           0 :         GET_MATRIX_CONVERT(q8, 1.0 / 256.0);
     515           0 :         break;
     516             :     case AV_MIX_COEFF_TYPE_Q15:
     517           0 :         GET_MATRIX_CONVERT(q15, 1.0 / 32768.0);
     518           0 :         break;
     519             :     case AV_MIX_COEFF_TYPE_FLT:
     520           0 :         GET_MATRIX_CONVERT(flt, 1.0);
     521           0 :         break;
     522             :     default:
     523           0 :         av_log(am->avr, AV_LOG_ERROR, "Invalid mix coeff type\n");
     524           0 :         return AVERROR(EINVAL);
     525             :     }
     526             : 
     527           0 :     return 0;
     528             : }
     529             : 
     530           0 : static void reduce_matrix(AudioMix *am, const double *matrix, int stride)
     531             : {
     532             :     int i, o;
     533             : 
     534           0 :     memset(am->output_zero, 0, sizeof(am->output_zero));
     535           0 :     memset(am->input_skip,  0, sizeof(am->input_skip));
     536           0 :     memset(am->output_skip, 0, sizeof(am->output_skip));
     537             : 
     538             :     /* exclude output channels if they can be zeroed instead of mixed */
     539           0 :     for (o = 0; o < am->out_channels; o++) {
     540           0 :         int zero = 1;
     541             : 
     542             :         /* check if the output is always silent */
     543           0 :         for (i = 0; i < am->in_channels; i++) {
     544           0 :             if (matrix[o * stride + i] != 0.0) {
     545           0 :                 zero = 0;
     546           0 :                 break;
     547             :             }
     548             :         }
     549             :         /* check if the corresponding input channel makes a contribution to
     550             :            any output channel */
     551           0 :         if (o < am->in_channels) {
     552           0 :             for (i = 0; i < am->out_channels; i++) {
     553           0 :                 if (matrix[i * stride + o] != 0.0) {
     554           0 :                     zero = 0;
     555           0 :                     break;
     556             :                 }
     557             :             }
     558             :         }
     559           0 :         if (zero) {
     560           0 :             am->output_zero[o] = 1;
     561           0 :             am->out_matrix_channels--;
     562           0 :             if (o < am->in_channels)
     563           0 :                 am->in_matrix_channels--;
     564             :         }
     565             :     }
     566           0 :     if (am->out_matrix_channels == 0 || am->in_matrix_channels == 0) {
     567           0 :         am->out_matrix_channels = 0;
     568           0 :         am->in_matrix_channels = 0;
     569           0 :         return;
     570             :     }
     571             : 
     572             :     /* skip input channels that contribute fully only to the corresponding
     573             :        output channel */
     574           0 :     for (i = 0; i < FFMIN(am->in_channels, am->out_channels); i++) {
     575           0 :         int skip = 1;
     576             : 
     577           0 :         for (o = 0; o < am->out_channels; o++) {
     578             :             int i0;
     579           0 :             if ((o != i && matrix[o * stride + i] != 0.0) ||
     580           0 :                 (o == i && matrix[o * stride + i] != 1.0)) {
     581           0 :                 skip = 0;
     582           0 :                 break;
     583             :             }
     584             :             /* if the input contributes fully to the output, also check that no
     585             :                other inputs contribute to this output */
     586           0 :             if (o == i) {
     587           0 :                 for (i0 = 0; i0 < am->in_channels; i0++) {
     588           0 :                     if (i0 != i && matrix[o * stride + i0] != 0.0) {
     589           0 :                         skip = 0;
     590           0 :                         break;
     591             :                     }
     592             :                 }
     593             :             }
     594             :         }
     595           0 :         if (skip) {
     596           0 :             am->input_skip[i] = 1;
     597           0 :             am->in_matrix_channels--;
     598             :         }
     599             :     }
     600             :     /* skip input channels that do not contribute to any output channel */
     601           0 :     for (; i < am->in_channels; i++) {
     602           0 :         int contrib = 0;
     603             : 
     604           0 :         for (o = 0; o < am->out_channels; o++) {
     605           0 :             if (matrix[o * stride + i] != 0.0) {
     606           0 :                 contrib = 1;
     607           0 :                 break;
     608             :             }
     609             :         }
     610           0 :         if (!contrib) {
     611           0 :             am->input_skip[i] = 1;
     612           0 :             am->in_matrix_channels--;
     613             :         }
     614             :     }
     615           0 :     if (am->in_matrix_channels == 0) {
     616           0 :         am->out_matrix_channels = 0;
     617           0 :         return;
     618             :     }
     619             : 
     620             :     /* skip output channels that only get full contribution from the
     621             :        corresponding input channel */
     622           0 :     for (o = 0; o < FFMIN(am->in_channels, am->out_channels); o++) {
     623           0 :         int skip = 1;
     624             :         int o0;
     625             : 
     626           0 :         for (i = 0; i < am->in_channels; i++) {
     627           0 :             if ((o != i && matrix[o * stride + i] != 0.0) ||
     628           0 :                 (o == i && matrix[o * stride + i] != 1.0)) {
     629           0 :                 skip = 0;
     630           0 :                 break;
     631             :             }
     632             :         }
     633             :         /* check if the corresponding input channel makes a contribution to
     634             :            any other output channel */
     635           0 :         i = o;
     636           0 :         for (o0 = 0; o0 < am->out_channels; o0++) {
     637           0 :             if (o0 != i && matrix[o0 * stride + i] != 0.0) {
     638           0 :                 skip = 0;
     639           0 :                 break;
     640             :             }
     641             :         }
     642           0 :         if (skip) {
     643           0 :             am->output_skip[o] = 1;
     644           0 :             am->out_matrix_channels--;
     645             :         }
     646             :     }
     647           0 :     if (am->out_matrix_channels == 0) {
     648           0 :         am->in_matrix_channels = 0;
     649           0 :         return;
     650             :     }
     651             : }
     652             : 
     653           0 : int ff_audio_mix_set_matrix(AudioMix *am, const double *matrix, int stride)
     654             : {
     655             :     int i, o, i0, o0, ret;
     656             :     char in_layout_name[128];
     657             :     char out_layout_name[128];
     658             : 
     659           0 :     if ( am->in_channels <= 0 ||  am->in_channels > AVRESAMPLE_MAX_CHANNELS ||
     660           0 :         am->out_channels <= 0 || am->out_channels > AVRESAMPLE_MAX_CHANNELS) {
     661           0 :         av_log(am->avr, AV_LOG_ERROR, "Invalid channel counts\n");
     662           0 :         return AVERROR(EINVAL);
     663             :     }
     664             : 
     665           0 :     if (am->matrix) {
     666           0 :         av_free(am->matrix[0]);
     667           0 :         am->matrix = NULL;
     668             :     }
     669             : 
     670           0 :     am->in_matrix_channels  = am->in_channels;
     671           0 :     am->out_matrix_channels = am->out_channels;
     672             : 
     673           0 :     reduce_matrix(am, matrix, stride);
     674             : 
     675             : #define CONVERT_MATRIX(type, expr)                                          \
     676             :     am->matrix_## type[0] = av_mallocz(am->out_matrix_channels *            \
     677             :                                        am->in_matrix_channels  *            \
     678             :                                        sizeof(*am->matrix_## type[0]));     \
     679             :     if (!am->matrix_## type[0])                                             \
     680             :         return AVERROR(ENOMEM);                                             \
     681             :     for (o = 0, o0 = 0; o < am->out_channels; o++) {                        \
     682             :         if (am->output_zero[o] || am->output_skip[o])                       \
     683             :             continue;                                                       \
     684             :         if (o0 > 0)                                                         \
     685             :             am->matrix_## type[o0] = am->matrix_## type[o0 - 1] +           \
     686             :                                      am->in_matrix_channels;                \
     687             :         for (i = 0, i0 = 0; i < am->in_channels; i++) {                     \
     688             :             double v;                                                       \
     689             :             if (am->input_skip[i] || am->output_zero[i])                    \
     690             :                 continue;                                                   \
     691             :             v = matrix[o * stride + i];                                     \
     692             :             am->matrix_## type[o0][i0] = expr;                              \
     693             :             i0++;                                                           \
     694             :         }                                                                   \
     695             :         o0++;                                                               \
     696             :     }                                                                       \
     697             :     am->matrix = (void **)am->matrix_## type;
     698             : 
     699           0 :     if (am->in_matrix_channels && am->out_matrix_channels) {
     700           0 :         switch (am->coeff_type) {
     701             :         case AV_MIX_COEFF_TYPE_Q8:
     702           0 :             CONVERT_MATRIX(q8, av_clip_int16(lrint(256.0 * v)))
     703           0 :             break;
     704             :         case AV_MIX_COEFF_TYPE_Q15:
     705           0 :             CONVERT_MATRIX(q15, av_clipl_int32(llrint(32768.0 * v)))
     706           0 :             break;
     707             :         case AV_MIX_COEFF_TYPE_FLT:
     708           0 :             CONVERT_MATRIX(flt, v)
     709           0 :             break;
     710             :         default:
     711           0 :             av_log(am->avr, AV_LOG_ERROR, "Invalid mix coeff type\n");
     712           0 :             return AVERROR(EINVAL);
     713             :         }
     714             :     }
     715             : 
     716           0 :     ret = mix_function_init(am);
     717           0 :     if (ret < 0)
     718           0 :         return ret;
     719             : 
     720           0 :     av_get_channel_layout_string(in_layout_name, sizeof(in_layout_name),
     721             :                                  am->in_channels, am->in_layout);
     722           0 :     av_get_channel_layout_string(out_layout_name, sizeof(out_layout_name),
     723             :                                  am->out_channels, am->out_layout);
     724           0 :     av_log(am->avr, AV_LOG_DEBUG, "audio_mix: %s to %s\n",
     725             :            in_layout_name, out_layout_name);
     726           0 :     av_log(am->avr, AV_LOG_DEBUG, "matrix size: %d x %d\n",
     727             :            am->in_matrix_channels, am->out_matrix_channels);
     728           0 :     for (o = 0; o < am->out_channels; o++) {
     729           0 :         for (i = 0; i < am->in_channels; i++) {
     730           0 :             if (am->output_zero[o])
     731           0 :                 av_log(am->avr, AV_LOG_DEBUG, "  (ZERO)");
     732           0 :             else if (am->input_skip[i] || am->output_zero[i] || am->output_skip[o])
     733           0 :                 av_log(am->avr, AV_LOG_DEBUG, "  (SKIP)");
     734             :             else
     735           0 :                 av_log(am->avr, AV_LOG_DEBUG, "  %0.3f ",
     736           0 :                        matrix[o * am->in_channels + i]);
     737             :         }
     738           0 :         av_log(am->avr, AV_LOG_DEBUG, "\n");
     739             :     }
     740             : 
     741           0 :     return 0;
     742             : }

Generated by: LCOV version 1.12