LCOV - code coverage report
Current view: top level - src/libswresample - rematrix.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 172 348 49.4 %
Date: 2017-01-19 23:52:33 Functions: 8 9 88.9 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2011-2012 Michael Niedermayer (michaelni@gmx.at)
       3             :  *
       4             :  * This file is part of libswresample
       5             :  *
       6             :  * libswresample 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             :  * libswresample 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 libswresample; if not, write to the Free Software
      18             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      19             :  */
      20             : 
      21             : #include "swresample_internal.h"
      22             : #include "libavutil/avassert.h"
      23             : #include "libavutil/channel_layout.h"
      24             : 
      25             : #define TEMPLATE_REMATRIX_FLT
      26             : #include "rematrix_template.c"
      27             : #undef TEMPLATE_REMATRIX_FLT
      28             : 
      29             : #define TEMPLATE_REMATRIX_DBL
      30             : #include "rematrix_template.c"
      31             : #undef TEMPLATE_REMATRIX_DBL
      32             : 
      33             : #define TEMPLATE_REMATRIX_S16
      34             : #include "rematrix_template.c"
      35             : #define TEMPLATE_CLIP
      36             : #include "rematrix_template.c"
      37             : #undef TEMPLATE_CLIP
      38             : #undef TEMPLATE_REMATRIX_S16
      39             : 
      40             : #define TEMPLATE_REMATRIX_S32
      41             : #include "rematrix_template.c"
      42             : #undef TEMPLATE_REMATRIX_S32
      43             : 
      44             : #define FRONT_LEFT             0
      45             : #define FRONT_RIGHT            1
      46             : #define FRONT_CENTER           2
      47             : #define LOW_FREQUENCY          3
      48             : #define BACK_LEFT              4
      49             : #define BACK_RIGHT             5
      50             : #define FRONT_LEFT_OF_CENTER   6
      51             : #define FRONT_RIGHT_OF_CENTER  7
      52             : #define BACK_CENTER            8
      53             : #define SIDE_LEFT              9
      54             : #define SIDE_RIGHT             10
      55             : #define TOP_CENTER             11
      56             : #define TOP_FRONT_LEFT         12
      57             : #define TOP_FRONT_CENTER       13
      58             : #define TOP_FRONT_RIGHT        14
      59             : #define TOP_BACK_LEFT          15
      60             : #define TOP_BACK_CENTER        16
      61             : #define TOP_BACK_RIGHT         17
      62             : #define NUM_NAMED_CHANNELS     18
      63             : 
      64           0 : int swr_set_matrix(struct SwrContext *s, const double *matrix, int stride)
      65             : {
      66             :     int nb_in, nb_out, in, out;
      67             : 
      68           0 :     if (!s || s->in_convert) // s needs to be allocated but not initialized
      69           0 :         return AVERROR(EINVAL);
      70           0 :     memset(s->matrix, 0, sizeof(s->matrix));
      71           0 :     memset(s->matrix_flt, 0, sizeof(s->matrix_flt));
      72           0 :     nb_in  = av_get_channel_layout_nb_channels(s->user_in_ch_layout);
      73           0 :     nb_out = av_get_channel_layout_nb_channels(s->user_out_ch_layout);
      74           0 :     for (out = 0; out < nb_out; out++) {
      75           0 :         for (in = 0; in < nb_in; in++)
      76           0 :             s->matrix_flt[out][in] = s->matrix[out][in] = matrix[in];
      77           0 :         matrix += stride;
      78             :     }
      79           0 :     s->rematrix_custom = 1;
      80           0 :     return 0;
      81             : }
      82             : 
      83          80 : static int even(int64_t layout){
      84          80 :     if(!layout) return 1;
      85          12 :     if(layout&(layout-1)) return 1;
      86           0 :     return 0;
      87             : }
      88             : 
      89          20 : static int clean_layout(void *s, int64_t layout){
      90          20 :     if(layout && layout != AV_CH_FRONT_CENTER && !(layout&(layout-1))) {
      91             :         char buf[128];
      92           0 :         av_get_channel_layout_string(buf, sizeof(buf), -1, layout);
      93           0 :         av_log(s, AV_LOG_VERBOSE, "Treating %s as mono\n", buf);
      94           0 :         return AV_CH_FRONT_CENTER;
      95             :     }
      96             : 
      97          20 :     return layout;
      98             : }
      99             : 
     100          20 : static int sane_layout(int64_t layout){
     101          20 :     if(!(layout & AV_CH_LAYOUT_SURROUND)) // at least 1 front speaker
     102           0 :         return 0;
     103          20 :     if(!even(layout & (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT))) // no asymetric front
     104           0 :         return 0;
     105          20 :     if(!even(layout & (AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT)))   // no asymetric side
     106           0 :         return 0;
     107          20 :     if(!even(layout & (AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT)))
     108           0 :         return 0;
     109          20 :     if(!even(layout & (AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER)))
     110           0 :         return 0;
     111          20 :     if(av_get_channel_layout_nb_channels(layout) >= SWR_CH_MAX)
     112           0 :         return 0;
     113             : 
     114          20 :     return 1;
     115             : }
     116             : 
     117          10 : av_cold int swr_build_matrix(uint64_t in_ch_layout_param, uint64_t out_ch_layout_param,
     118             :                              double center_mix_level, double surround_mix_level,
     119             :                              double lfe_mix_level, double maxval,
     120             :                              double rematrix_volume, double *matrix_param,
     121             :                              int stride, enum AVMatrixEncoding matrix_encoding, void *log_context)
     122             : {
     123             :     int i, j, out_i;
     124          10 :     double matrix[NUM_NAMED_CHANNELS][NUM_NAMED_CHANNELS]={{0}};
     125             :     int64_t unaccounted, in_ch_layout, out_ch_layout;
     126          10 :     double maxcoef=0;
     127             :     char buf[128];
     128             : 
     129          10 :      in_ch_layout = clean_layout(log_context,  in_ch_layout_param);
     130          10 :     out_ch_layout = clean_layout(log_context, out_ch_layout_param);
     131             : 
     132          10 :     if(   out_ch_layout == AV_CH_LAYOUT_STEREO_DOWNMIX
     133           0 :        && (in_ch_layout & AV_CH_LAYOUT_STEREO_DOWNMIX) == 0
     134             :     )
     135           0 :         out_ch_layout = AV_CH_LAYOUT_STEREO;
     136             : 
     137          10 :     if(    in_ch_layout == AV_CH_LAYOUT_STEREO_DOWNMIX
     138           0 :        && (out_ch_layout & AV_CH_LAYOUT_STEREO_DOWNMIX) == 0
     139             :     )
     140           0 :         in_ch_layout = AV_CH_LAYOUT_STEREO;
     141             : 
     142          10 :     if(!sane_layout(in_ch_layout)){
     143           0 :         av_get_channel_layout_string(buf, sizeof(buf), -1, in_ch_layout_param);
     144           0 :         av_log(log_context, AV_LOG_ERROR, "Input channel layout '%s' is not supported\n", buf);
     145           0 :         return AVERROR(EINVAL);
     146             :     }
     147             : 
     148          10 :     if(!sane_layout(out_ch_layout)){
     149           0 :         av_get_channel_layout_string(buf, sizeof(buf), -1, out_ch_layout_param);
     150           0 :         av_log(log_context, AV_LOG_ERROR, "Output channel layout '%s' is not supported\n", buf);
     151           0 :         return AVERROR(EINVAL);
     152             :     }
     153             : 
     154         190 :     for(i=0; i<FF_ARRAY_ELEMS(matrix); i++){
     155         180 :         if(in_ch_layout & out_ch_layout & (1ULL<<i))
     156           2 :             matrix[i][i]= 1.0;
     157             :     }
     158             : 
     159          10 :     unaccounted= in_ch_layout & ~out_ch_layout;
     160             : 
     161             : //FIXME implement dolby surround
     162             : //FIXME implement full ac3
     163             : 
     164             : 
     165          10 :     if(unaccounted & AV_CH_FRONT_CENTER){
     166           3 :         if((out_ch_layout & AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO){
     167           3 :             if(in_ch_layout & AV_CH_LAYOUT_STEREO) {
     168           0 :                 matrix[ FRONT_LEFT][FRONT_CENTER]+= center_mix_level;
     169           0 :                 matrix[FRONT_RIGHT][FRONT_CENTER]+= center_mix_level;
     170             :             } else {
     171           3 :                 matrix[ FRONT_LEFT][FRONT_CENTER]+= M_SQRT1_2;
     172           3 :                 matrix[FRONT_RIGHT][FRONT_CENTER]+= M_SQRT1_2;
     173             :             }
     174             :         }else
     175           0 :             av_assert0(0);
     176             :     }
     177          10 :     if(unaccounted & AV_CH_LAYOUT_STEREO){
     178           6 :         if(out_ch_layout & AV_CH_FRONT_CENTER){
     179           6 :             matrix[FRONT_CENTER][ FRONT_LEFT]+= M_SQRT1_2;
     180           6 :             matrix[FRONT_CENTER][FRONT_RIGHT]+= M_SQRT1_2;
     181           6 :             if(in_ch_layout & AV_CH_FRONT_CENTER)
     182           0 :                 matrix[FRONT_CENTER][ FRONT_CENTER] = center_mix_level*sqrt(2);
     183             :         }else
     184           0 :             av_assert0(0);
     185             :     }
     186             : 
     187          10 :     if(unaccounted & AV_CH_BACK_CENTER){
     188           0 :         if(out_ch_layout & AV_CH_BACK_LEFT){
     189           0 :             matrix[ BACK_LEFT][BACK_CENTER]+= M_SQRT1_2;
     190           0 :             matrix[BACK_RIGHT][BACK_CENTER]+= M_SQRT1_2;
     191           0 :         }else if(out_ch_layout & AV_CH_SIDE_LEFT){
     192           0 :             matrix[ SIDE_LEFT][BACK_CENTER]+= M_SQRT1_2;
     193           0 :             matrix[SIDE_RIGHT][BACK_CENTER]+= M_SQRT1_2;
     194           0 :         }else if(out_ch_layout & AV_CH_FRONT_LEFT){
     195           0 :             if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY ||
     196             :                 matrix_encoding == AV_MATRIX_ENCODING_DPLII) {
     197           0 :                 if (unaccounted & (AV_CH_BACK_LEFT | AV_CH_SIDE_LEFT)) {
     198           0 :                     matrix[FRONT_LEFT ][BACK_CENTER] -= surround_mix_level * M_SQRT1_2;
     199           0 :                     matrix[FRONT_RIGHT][BACK_CENTER] += surround_mix_level * M_SQRT1_2;
     200             :                 } else {
     201           0 :                     matrix[FRONT_LEFT ][BACK_CENTER] -= surround_mix_level;
     202           0 :                     matrix[FRONT_RIGHT][BACK_CENTER] += surround_mix_level;
     203             :                 }
     204             :             } else {
     205           0 :                 matrix[ FRONT_LEFT][BACK_CENTER]+= surround_mix_level * M_SQRT1_2;
     206           0 :                 matrix[FRONT_RIGHT][BACK_CENTER]+= surround_mix_level * M_SQRT1_2;
     207             :             }
     208           0 :         }else if(out_ch_layout & AV_CH_FRONT_CENTER){
     209           0 :             matrix[ FRONT_CENTER][BACK_CENTER]+= surround_mix_level * M_SQRT1_2;
     210             :         }else
     211           0 :             av_assert0(0);
     212             :     }
     213          10 :     if(unaccounted & AV_CH_BACK_LEFT){
     214           0 :         if(out_ch_layout & AV_CH_BACK_CENTER){
     215           0 :             matrix[BACK_CENTER][ BACK_LEFT]+= M_SQRT1_2;
     216           0 :             matrix[BACK_CENTER][BACK_RIGHT]+= M_SQRT1_2;
     217           0 :         }else if(out_ch_layout & AV_CH_SIDE_LEFT){
     218           0 :             if(in_ch_layout & AV_CH_SIDE_LEFT){
     219           0 :                 matrix[ SIDE_LEFT][ BACK_LEFT]+= M_SQRT1_2;
     220           0 :                 matrix[SIDE_RIGHT][BACK_RIGHT]+= M_SQRT1_2;
     221             :             }else{
     222           0 :             matrix[ SIDE_LEFT][ BACK_LEFT]+= 1.0;
     223           0 :             matrix[SIDE_RIGHT][BACK_RIGHT]+= 1.0;
     224             :             }
     225           0 :         }else if(out_ch_layout & AV_CH_FRONT_LEFT){
     226           0 :             if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY) {
     227           0 :                 matrix[FRONT_LEFT ][BACK_LEFT ] -= surround_mix_level * M_SQRT1_2;
     228           0 :                 matrix[FRONT_LEFT ][BACK_RIGHT] -= surround_mix_level * M_SQRT1_2;
     229           0 :                 matrix[FRONT_RIGHT][BACK_LEFT ] += surround_mix_level * M_SQRT1_2;
     230           0 :                 matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level * M_SQRT1_2;
     231           0 :             } else if (matrix_encoding == AV_MATRIX_ENCODING_DPLII) {
     232           0 :                 matrix[FRONT_LEFT ][BACK_LEFT ] -= surround_mix_level * SQRT3_2;
     233           0 :                 matrix[FRONT_LEFT ][BACK_RIGHT] -= surround_mix_level * M_SQRT1_2;
     234           0 :                 matrix[FRONT_RIGHT][BACK_LEFT ] += surround_mix_level * M_SQRT1_2;
     235           0 :                 matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level * SQRT3_2;
     236             :             } else {
     237           0 :                 matrix[ FRONT_LEFT][ BACK_LEFT] += surround_mix_level;
     238           0 :                 matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level;
     239             :             }
     240           0 :         }else if(out_ch_layout & AV_CH_FRONT_CENTER){
     241           0 :             matrix[ FRONT_CENTER][BACK_LEFT ]+= surround_mix_level*M_SQRT1_2;
     242           0 :             matrix[ FRONT_CENTER][BACK_RIGHT]+= surround_mix_level*M_SQRT1_2;
     243             :         }else
     244           0 :             av_assert0(0);
     245             :     }
     246             : 
     247          10 :     if(unaccounted & AV_CH_SIDE_LEFT){
     248           0 :         if(out_ch_layout & AV_CH_BACK_LEFT){
     249             :             /* if back channels do not exist in the input, just copy side
     250             :                channels to back channels, otherwise mix side into back */
     251           0 :             if (in_ch_layout & AV_CH_BACK_LEFT) {
     252           0 :                 matrix[BACK_LEFT ][SIDE_LEFT ] += M_SQRT1_2;
     253           0 :                 matrix[BACK_RIGHT][SIDE_RIGHT] += M_SQRT1_2;
     254             :             } else {
     255           0 :                 matrix[BACK_LEFT ][SIDE_LEFT ] += 1.0;
     256           0 :                 matrix[BACK_RIGHT][SIDE_RIGHT] += 1.0;
     257             :             }
     258           0 :         }else if(out_ch_layout & AV_CH_BACK_CENTER){
     259           0 :             matrix[BACK_CENTER][ SIDE_LEFT]+= M_SQRT1_2;
     260           0 :             matrix[BACK_CENTER][SIDE_RIGHT]+= M_SQRT1_2;
     261           0 :         }else if(out_ch_layout & AV_CH_FRONT_LEFT){
     262           0 :             if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY) {
     263           0 :                 matrix[FRONT_LEFT ][SIDE_LEFT ] -= surround_mix_level * M_SQRT1_2;
     264           0 :                 matrix[FRONT_LEFT ][SIDE_RIGHT] -= surround_mix_level * M_SQRT1_2;
     265           0 :                 matrix[FRONT_RIGHT][SIDE_LEFT ] += surround_mix_level * M_SQRT1_2;
     266           0 :                 matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level * M_SQRT1_2;
     267           0 :             } else if (matrix_encoding == AV_MATRIX_ENCODING_DPLII) {
     268           0 :                 matrix[FRONT_LEFT ][SIDE_LEFT ] -= surround_mix_level * SQRT3_2;
     269           0 :                 matrix[FRONT_LEFT ][SIDE_RIGHT] -= surround_mix_level * M_SQRT1_2;
     270           0 :                 matrix[FRONT_RIGHT][SIDE_LEFT ] += surround_mix_level * M_SQRT1_2;
     271           0 :                 matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level * SQRT3_2;
     272             :             } else {
     273           0 :                 matrix[ FRONT_LEFT][ SIDE_LEFT] += surround_mix_level;
     274           0 :                 matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level;
     275             :             }
     276           0 :         }else if(out_ch_layout & AV_CH_FRONT_CENTER){
     277           0 :             matrix[ FRONT_CENTER][SIDE_LEFT ]+= surround_mix_level * M_SQRT1_2;
     278           0 :             matrix[ FRONT_CENTER][SIDE_RIGHT]+= surround_mix_level * M_SQRT1_2;
     279             :         }else
     280           0 :             av_assert0(0);
     281             :     }
     282             : 
     283          10 :     if(unaccounted & AV_CH_FRONT_LEFT_OF_CENTER){
     284           0 :         if(out_ch_layout & AV_CH_FRONT_LEFT){
     285           0 :             matrix[ FRONT_LEFT][ FRONT_LEFT_OF_CENTER]+= 1.0;
     286           0 :             matrix[FRONT_RIGHT][FRONT_RIGHT_OF_CENTER]+= 1.0;
     287           0 :         }else if(out_ch_layout & AV_CH_FRONT_CENTER){
     288           0 :             matrix[ FRONT_CENTER][ FRONT_LEFT_OF_CENTER]+= M_SQRT1_2;
     289           0 :             matrix[ FRONT_CENTER][FRONT_RIGHT_OF_CENTER]+= M_SQRT1_2;
     290             :         }else
     291           0 :             av_assert0(0);
     292             :     }
     293             :     /* mix LFE into front left/right or center */
     294          10 :     if (unaccounted & AV_CH_LOW_FREQUENCY) {
     295           0 :         if (out_ch_layout & AV_CH_FRONT_CENTER) {
     296           0 :             matrix[FRONT_CENTER][LOW_FREQUENCY] += lfe_mix_level;
     297           0 :         } else if (out_ch_layout & AV_CH_FRONT_LEFT) {
     298           0 :             matrix[FRONT_LEFT ][LOW_FREQUENCY] += lfe_mix_level * M_SQRT1_2;
     299           0 :             matrix[FRONT_RIGHT][LOW_FREQUENCY] += lfe_mix_level * M_SQRT1_2;
     300             :         } else
     301           0 :             av_assert0(0);
     302             :     }
     303             : 
     304         650 :     for(out_i=i=0; i<64; i++){
     305         640 :         double sum=0;
     306         640 :         int in_i=0;
     307         640 :         if((out_ch_layout & (1ULL<<i)) == 0)
     308         622 :             continue;
     309        1170 :         for(j=0; j<64; j++){
     310        1152 :             if((in_ch_layout & (1ULL<<j)) == 0)
     311        1122 :                continue;
     312          30 :             if (i < FF_ARRAY_ELEMS(matrix) && j < FF_ARRAY_ELEMS(matrix[0]))
     313          30 :                 matrix_param[stride*out_i + in_i] = matrix[i][j];
     314             :             else
     315           0 :                 matrix_param[stride*out_i + in_i] = i == j && (in_ch_layout & out_ch_layout & (1ULL<<i));
     316          30 :             sum += fabs(matrix_param[stride*out_i + in_i]);
     317          30 :             in_i++;
     318             :         }
     319          18 :         maxcoef= FFMAX(maxcoef, sum);
     320          18 :         out_i++;
     321             :     }
     322          10 :     if(rematrix_volume  < 0)
     323           0 :         maxcoef = -rematrix_volume;
     324             : 
     325          10 :     if(maxcoef > maxval || rematrix_volume  < 0){
     326           6 :         maxcoef /= maxval;
     327         390 :         for(i=0; i<SWR_CH_MAX; i++)
     328       24960 :             for(j=0; j<SWR_CH_MAX; j++){
     329       24576 :                 matrix_param[stride*i + j] /= maxcoef;
     330             :             }
     331             :     }
     332             : 
     333          10 :     if(rematrix_volume > 0){
     334         650 :         for(i=0; i<SWR_CH_MAX; i++)
     335       41600 :             for(j=0; j<SWR_CH_MAX; j++){
     336       40960 :                 matrix_param[stride*i + j] *= rematrix_volume;
     337             :             }
     338             :     }
     339             : 
     340          10 :     av_log(log_context, AV_LOG_DEBUG, "Matrix coefficients:\n");
     341          28 :     for(i=0; i<av_get_channel_layout_nb_channels(out_ch_layout); i++){
     342          18 :         const char *c =
     343          18 :             av_get_channel_name(av_channel_layout_extract_channel(out_ch_layout, i));
     344          18 :         av_log(log_context, AV_LOG_DEBUG, "%s: ", c ? c : "?");
     345          48 :         for(j=0; j<av_get_channel_layout_nb_channels(in_ch_layout); j++){
     346          30 :             c = av_get_channel_name(av_channel_layout_extract_channel(in_ch_layout, j));
     347          30 :             av_log(log_context, AV_LOG_DEBUG, "%s:%f ", c ? c : "?", matrix_param[stride*i + j]);
     348             :         }
     349          18 :         av_log(log_context, AV_LOG_DEBUG, "\n");
     350             :     }
     351          10 :     return 0;
     352             : }
     353             : 
     354          10 : av_cold static int auto_matrix(SwrContext *s)
     355             : {
     356             :     double maxval;
     357             :     int ret;
     358             : 
     359          10 :     if (s->rematrix_maxval > 0) {
     360           0 :         maxval = s->rematrix_maxval;
     361          10 :     } else if (   av_get_packed_sample_fmt(s->out_sample_fmt) < AV_SAMPLE_FMT_FLT
     362           1 :                || av_get_packed_sample_fmt(s->int_sample_fmt) < AV_SAMPLE_FMT_FLT) {
     363           9 :         maxval = 1.0;
     364             :     } else
     365           1 :         maxval = INT_MAX;
     366             : 
     367          10 :     memset(s->matrix, 0, sizeof(s->matrix));
     368          50 :     ret = swr_build_matrix(s->in_ch_layout, s->out_ch_layout,
     369          30 :                            s->clev, s->slev, s->lfe_mix_level,
     370          10 :                            maxval, s->rematrix_volume, (double*)s->matrix,
     371          10 :                            s->matrix[1] - s->matrix[0], s->matrix_encoding, s);
     372             : 
     373          10 :     if (ret >= 0 && s->int_sample_fmt == AV_SAMPLE_FMT_FLTP) {
     374             :         int i;
     375       28679 :         for (i = 0; i < FF_ARRAY_ELEMS(s->matrix[0])*FF_ARRAY_ELEMS(s->matrix[0]); i++)
     376       28672 :             s->matrix_flt[0][i] = s->matrix[0][i];
     377             :     }
     378             : 
     379          10 :     return ret;
     380             : }
     381             : 
     382          10 : av_cold int swri_rematrix_init(SwrContext *s){
     383             :     int i, j;
     384          10 :     int nb_in  = av_get_channel_layout_nb_channels(s->in_ch_layout);
     385          10 :     int nb_out = av_get_channel_layout_nb_channels(s->out_ch_layout);
     386             : 
     387          10 :     s->mix_any_f = NULL;
     388             : 
     389          10 :     if (!s->rematrix_custom) {
     390          10 :         int r = auto_matrix(s);
     391          10 :         if (r)
     392           0 :             return r;
     393             :     }
     394          10 :     if (s->midbuf.fmt == AV_SAMPLE_FMT_S16P){
     395           3 :         int maxsum = 0;
     396           3 :         s->native_matrix = av_calloc(nb_in * nb_out, sizeof(int));
     397           3 :         s->native_one    = av_mallocz(sizeof(int));
     398           3 :         if (!s->native_matrix || !s->native_one)
     399           0 :             return AVERROR(ENOMEM);
     400           8 :         for (i = 0; i < nb_out; i++) {
     401           5 :             double rem = 0;
     402           5 :             int sum = 0;
     403             : 
     404          11 :             for (j = 0; j < nb_in; j++) {
     405           6 :                 double target = s->matrix[i][j] * 32768 + rem;
     406           6 :                 ((int*)s->native_matrix)[i * nb_in + j] = lrintf(target);
     407           6 :                 rem += target - ((int*)s->native_matrix)[i * nb_in + j];
     408           6 :                 sum += FFABS(((int*)s->native_matrix)[i * nb_in + j]);
     409             :             }
     410           5 :             maxsum = FFMAX(maxsum, sum);
     411             :         }
     412           3 :         *((int*)s->native_one) = 32768;
     413           3 :         if (maxsum <= 32768) {
     414           3 :             s->mix_1_1_f = (mix_1_1_func_type*)copy_s16;
     415           3 :             s->mix_2_1_f = (mix_2_1_func_type*)sum2_s16;
     416           3 :             s->mix_any_f = (mix_any_func_type*)get_mix_any_func_s16(s);
     417             :         } else {
     418           0 :             s->mix_1_1_f = (mix_1_1_func_type*)copy_clip_s16;
     419           0 :             s->mix_2_1_f = (mix_2_1_func_type*)sum2_clip_s16;
     420           0 :             s->mix_any_f = (mix_any_func_type*)get_mix_any_func_clip_s16(s);
     421             :         }
     422           7 :     }else if(s->midbuf.fmt == AV_SAMPLE_FMT_FLTP){
     423           7 :         s->native_matrix = av_calloc(nb_in * nb_out, sizeof(float));
     424           7 :         s->native_one    = av_mallocz(sizeof(float));
     425           7 :         if (!s->native_matrix || !s->native_one)
     426           0 :             return AVERROR(ENOMEM);
     427          20 :         for (i = 0; i < nb_out; i++)
     428          37 :             for (j = 0; j < nb_in; j++)
     429          24 :                 ((float*)s->native_matrix)[i * nb_in + j] = s->matrix[i][j];
     430           7 :         *((float*)s->native_one) = 1.0;
     431           7 :         s->mix_1_1_f = (mix_1_1_func_type*)copy_float;
     432           7 :         s->mix_2_1_f = (mix_2_1_func_type*)sum2_float;
     433           7 :         s->mix_any_f = (mix_any_func_type*)get_mix_any_func_float(s);
     434           0 :     }else if(s->midbuf.fmt == AV_SAMPLE_FMT_DBLP){
     435           0 :         s->native_matrix = av_calloc(nb_in * nb_out, sizeof(double));
     436           0 :         s->native_one    = av_mallocz(sizeof(double));
     437           0 :         if (!s->native_matrix || !s->native_one)
     438           0 :             return AVERROR(ENOMEM);
     439           0 :         for (i = 0; i < nb_out; i++)
     440           0 :             for (j = 0; j < nb_in; j++)
     441           0 :                 ((double*)s->native_matrix)[i * nb_in + j] = s->matrix[i][j];
     442           0 :         *((double*)s->native_one) = 1.0;
     443           0 :         s->mix_1_1_f = (mix_1_1_func_type*)copy_double;
     444           0 :         s->mix_2_1_f = (mix_2_1_func_type*)sum2_double;
     445           0 :         s->mix_any_f = (mix_any_func_type*)get_mix_any_func_double(s);
     446           0 :     }else if(s->midbuf.fmt == AV_SAMPLE_FMT_S32P){
     447             :         // Only for dithering currently
     448             : //         s->native_matrix = av_calloc(nb_in * nb_out, sizeof(double));
     449           0 :         s->native_one    = av_mallocz(sizeof(int));
     450           0 :         if (!s->native_one)
     451           0 :             return AVERROR(ENOMEM);
     452             : //         for (i = 0; i < nb_out; i++)
     453             : //             for (j = 0; j < nb_in; j++)
     454             : //                 ((double*)s->native_matrix)[i * nb_in + j] = s->matrix[i][j];
     455           0 :         *((int*)s->native_one) = 32768;
     456           0 :         s->mix_1_1_f = (mix_1_1_func_type*)copy_s32;
     457           0 :         s->mix_2_1_f = (mix_2_1_func_type*)sum2_s32;
     458           0 :         s->mix_any_f = (mix_any_func_type*)get_mix_any_func_s32(s);
     459             :     }else
     460           0 :         av_assert0(0);
     461             :     //FIXME quantize for integeres
     462         650 :     for (i = 0; i < SWR_CH_MAX; i++) {
     463         640 :         int ch_in=0;
     464       41600 :         for (j = 0; j < SWR_CH_MAX; j++) {
     465       40960 :             s->matrix32[i][j]= lrintf(s->matrix[i][j] * 32768);
     466       40960 :             if(s->matrix[i][j])
     467          20 :                 s->matrix_ch[i][++ch_in]= j;
     468             :         }
     469         640 :         s->matrix_ch[i][0]= ch_in;
     470             :     }
     471             : 
     472             :     if(HAVE_YASM && HAVE_MMX)
     473          10 :         return swri_rematrix_init_x86(s);
     474             : 
     475             :     return 0;
     476             : }
     477             : 
     478        2208 : av_cold void swri_rematrix_free(SwrContext *s){
     479        2208 :     av_freep(&s->native_matrix);
     480        2208 :     av_freep(&s->native_one);
     481        2208 :     av_freep(&s->native_simd_matrix);
     482        2208 :     av_freep(&s->native_simd_one);
     483        2208 : }
     484             : 
     485         853 : int swri_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mustcopy){
     486             :     int out_i, in_i, i, j;
     487         853 :     int len1 = 0;
     488         853 :     int off = 0;
     489             : 
     490         853 :     if(s->mix_any_f) {
     491           0 :         s->mix_any_f(out->ch, (const uint8_t **)in->ch, s->native_matrix, len);
     492           0 :         return 0;
     493             :     }
     494             : 
     495         853 :     if(s->mix_2_1_simd || s->mix_1_1_simd){
     496          47 :         len1= len&~15;
     497          47 :         off = len1 * out->bps;
     498             :     }
     499             : 
     500         853 :     av_assert0(!s->out_ch_layout || out->ch_count == av_get_channel_layout_nb_channels(s->out_ch_layout));
     501         853 :     av_assert0(!s-> in_ch_layout || in ->ch_count == av_get_channel_layout_nb_channels(s-> in_ch_layout));
     502             : 
     503        2458 :     for(out_i=0; out_i<out->ch_count; out_i++){
     504        1605 :         switch(s->matrix_ch[out_i][0]){
     505             :         case 0:
     506         492 :             if(mustcopy)
     507           0 :                 memset(out->ch[out_i], 0, len * av_get_bytes_per_sample(s->int_sample_fmt));
     508         492 :             break;
     509             :         case 1:
     510         520 :             in_i= s->matrix_ch[out_i][1];
     511         520 :             if(s->matrix[out_i][in_i]!=1.0){
     512         274 :                 if(s->mix_1_1_simd && len1)
     513          94 :                     s->mix_1_1_simd(out->ch[out_i]    , in->ch[in_i]    , s->native_simd_matrix, in->ch_count*out_i + in_i, len1);
     514         274 :                 if(len != len1)
     515         180 :                     s->mix_1_1_f   (out->ch[out_i]+off, in->ch[in_i]+off, s->native_matrix, in->ch_count*out_i + in_i, len-len1);
     516         246 :             }else if(mustcopy){
     517           0 :                 memcpy(out->ch[out_i], in->ch[in_i], len*out->bps);
     518             :             }else{
     519         246 :                 out->ch[out_i]= in->ch[in_i];
     520             :             }
     521         520 :             break;
     522             :         case 2: {
     523         593 :             int in_i1 = s->matrix_ch[out_i][1];
     524         593 :             int in_i2 = s->matrix_ch[out_i][2];
     525         593 :             if(s->mix_2_1_simd && len1)
     526           0 :                 s->mix_2_1_simd(out->ch[out_i]    , in->ch[in_i1]    , in->ch[in_i2]    , s->native_simd_matrix, in->ch_count*out_i + in_i1, in->ch_count*out_i + in_i2, len1);
     527             :             else
     528         593 :                 s->mix_2_1_f   (out->ch[out_i]    , in->ch[in_i1]    , in->ch[in_i2]    , s->native_matrix, in->ch_count*out_i + in_i1, in->ch_count*out_i + in_i2, len1);
     529         593 :             if(len != len1)
     530         591 :                 s->mix_2_1_f   (out->ch[out_i]+off, in->ch[in_i1]+off, in->ch[in_i2]+off, s->native_matrix, in->ch_count*out_i + in_i1, in->ch_count*out_i + in_i2, len-len1);
     531         593 :             break;}
     532             :         default:
     533           0 :             if(s->int_sample_fmt == AV_SAMPLE_FMT_FLTP){
     534           0 :                 for(i=0; i<len; i++){
     535           0 :                     float v=0;
     536           0 :                     for(j=0; j<s->matrix_ch[out_i][0]; j++){
     537           0 :                         in_i= s->matrix_ch[out_i][1+j];
     538           0 :                         v+= ((float*)in->ch[in_i])[i] * s->matrix_flt[out_i][in_i];
     539             :                     }
     540           0 :                     ((float*)out->ch[out_i])[i]= v;
     541             :                 }
     542           0 :             }else if(s->int_sample_fmt == AV_SAMPLE_FMT_DBLP){
     543           0 :                 for(i=0; i<len; i++){
     544           0 :                     double v=0;
     545           0 :                     for(j=0; j<s->matrix_ch[out_i][0]; j++){
     546           0 :                         in_i= s->matrix_ch[out_i][1+j];
     547           0 :                         v+= ((double*)in->ch[in_i])[i] * s->matrix[out_i][in_i];
     548             :                     }
     549           0 :                     ((double*)out->ch[out_i])[i]= v;
     550             :                 }
     551             :             }else{
     552           0 :                 for(i=0; i<len; i++){
     553           0 :                     int v=0;
     554           0 :                     for(j=0; j<s->matrix_ch[out_i][0]; j++){
     555           0 :                         in_i= s->matrix_ch[out_i][1+j];
     556           0 :                         v+= ((int16_t*)in->ch[in_i])[i] * s->matrix32[out_i][in_i];
     557             :                     }
     558           0 :                     ((int16_t*)out->ch[out_i])[i]= (v + 16384)>>15;
     559             :                 }
     560             :             }
     561             :         }
     562             :     }
     563         853 :     return 0;
     564             : }

Generated by: LCOV version 1.12