av_cold int swr_build_matrix(uint64_t in_ch_layout_param, uint64_t out_ch_layout_param, double center_mix_level, double surround_mix_level, double lfe_mix_level, double maxval, double rematrix_volume, double *matrix_param, int stride, enum AVMatrixEncoding matrix_encoding, void *log_context) { int i, j, out_i; double matrix[NUM_NAMED_CHANNELS][NUM_NAMED_CHANNELS]={{0}}; int64_t unaccounted, in_ch_layout, out_ch_layout; double maxcoef=0; char buf[128]; in_ch_layout = clean_layout(log_context, in_ch_layout_param); out_ch_layout = clean_layout(log_context, out_ch_layout_param); if( out_ch_layout == AV_CH_LAYOUT_STEREO_DOWNMIX && (in_ch_layout & AV_CH_LAYOUT_STEREO_DOWNMIX) == 0 ) out_ch_layout = AV_CH_LAYOUT_STEREO; if( in_ch_layout == AV_CH_LAYOUT_STEREO_DOWNMIX && (out_ch_layout & AV_CH_LAYOUT_STEREO_DOWNMIX) == 0 ) in_ch_layout = AV_CH_LAYOUT_STEREO; if(!sane_layout(in_ch_layout)){ av_get_channel_layout_string(buf, sizeof(buf), -1, in_ch_layout_param); av_log(log_context, AV_LOG_ERROR, "Input channel layout '%s' is not supported\n", buf); return AVERROR(EINVAL); } if(!sane_layout(out_ch_layout)){ av_get_channel_layout_string(buf, sizeof(buf), -1, out_ch_layout_param); av_log(log_context, AV_LOG_ERROR, "Output channel layout '%s' is not supported\n", buf); return AVERROR(EINVAL); } for(i=0; i<FF_ARRAY_ELEMS(matrix); i++){ if(in_ch_layout & out_ch_layout & (1ULL<<i)) matrix[i][i]= 1.0; } unaccounted= in_ch_layout & ~out_ch_layout; //FIXME implement dolby surround //FIXME implement full ac3 if(unaccounted & AV_CH_FRONT_CENTER){ if((out_ch_layout & AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO){ if(in_ch_layout & AV_CH_LAYOUT_STEREO) { matrix[ FRONT_LEFT][FRONT_CENTER]+= center_mix_level; matrix[FRONT_RIGHT][FRONT_CENTER]+= center_mix_level; } else { matrix[ FRONT_LEFT][FRONT_CENTER]+= M_SQRT1_2; matrix[FRONT_RIGHT][FRONT_CENTER]+= M_SQRT1_2; } }else av_assert0(0); } if(unaccounted & AV_CH_LAYOUT_STEREO){ if(out_ch_layout & AV_CH_FRONT_CENTER){ matrix[FRONT_CENTER][ FRONT_LEFT]+= M_SQRT1_2; matrix[FRONT_CENTER][FRONT_RIGHT]+= M_SQRT1_2; if(in_ch_layout & AV_CH_FRONT_CENTER) matrix[FRONT_CENTER][ FRONT_CENTER] = center_mix_level*sqrt(2); }else av_assert0(0); } if(unaccounted & AV_CH_BACK_CENTER){ if(out_ch_layout & AV_CH_BACK_LEFT){ matrix[ BACK_LEFT][BACK_CENTER]+= M_SQRT1_2; matrix[BACK_RIGHT][BACK_CENTER]+= M_SQRT1_2; }else if(out_ch_layout & AV_CH_SIDE_LEFT){ matrix[ SIDE_LEFT][BACK_CENTER]+= M_SQRT1_2; matrix[SIDE_RIGHT][BACK_CENTER]+= M_SQRT1_2; }else if(out_ch_layout & AV_CH_FRONT_LEFT){ if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY || matrix_encoding == AV_MATRIX_ENCODING_DPLII) { if (unaccounted & (AV_CH_BACK_LEFT | AV_CH_SIDE_LEFT)) { matrix[FRONT_LEFT ][BACK_CENTER] -= surround_mix_level * M_SQRT1_2; matrix[FRONT_RIGHT][BACK_CENTER] += surround_mix_level * M_SQRT1_2; } else { matrix[FRONT_LEFT ][BACK_CENTER] -= surround_mix_level; matrix[FRONT_RIGHT][BACK_CENTER] += surround_mix_level; } } else { matrix[ FRONT_LEFT][BACK_CENTER]+= surround_mix_level * M_SQRT1_2; matrix[FRONT_RIGHT][BACK_CENTER]+= surround_mix_level * M_SQRT1_2; } }else if(out_ch_layout & AV_CH_FRONT_CENTER){ matrix[ FRONT_CENTER][BACK_CENTER]+= surround_mix_level * M_SQRT1_2; }else av_assert0(0); } if(unaccounted & AV_CH_BACK_LEFT){ if(out_ch_layout & AV_CH_BACK_CENTER){ matrix[BACK_CENTER][ BACK_LEFT]+= M_SQRT1_2; matrix[BACK_CENTER][BACK_RIGHT]+= M_SQRT1_2; }else if(out_ch_layout & AV_CH_SIDE_LEFT){ if(in_ch_layout & AV_CH_SIDE_LEFT){ matrix[ SIDE_LEFT][ BACK_LEFT]+= M_SQRT1_2; matrix[SIDE_RIGHT][BACK_RIGHT]+= M_SQRT1_2; }else{ matrix[ SIDE_LEFT][ BACK_LEFT]+= 1.0; matrix[SIDE_RIGHT][BACK_RIGHT]+= 1.0; } }else if(out_ch_layout & AV_CH_FRONT_LEFT){ if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY) { matrix[FRONT_LEFT ][BACK_LEFT ] -= surround_mix_level * M_SQRT1_2; matrix[FRONT_LEFT ][BACK_RIGHT] -= surround_mix_level * M_SQRT1_2; matrix[FRONT_RIGHT][BACK_LEFT ] += surround_mix_level * M_SQRT1_2; matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level * M_SQRT1_2; } else if (matrix_encoding == AV_MATRIX_ENCODING_DPLII) { matrix[FRONT_LEFT ][BACK_LEFT ] -= surround_mix_level * SQRT3_2; matrix[FRONT_LEFT ][BACK_RIGHT] -= surround_mix_level * M_SQRT1_2; matrix[FRONT_RIGHT][BACK_LEFT ] += surround_mix_level * M_SQRT1_2; matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level * SQRT3_2; } else { matrix[ FRONT_LEFT][ BACK_LEFT] += surround_mix_level; matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level; } }else if(out_ch_layout & AV_CH_FRONT_CENTER){ matrix[ FRONT_CENTER][BACK_LEFT ]+= surround_mix_level*M_SQRT1_2; matrix[ FRONT_CENTER][BACK_RIGHT]+= surround_mix_level*M_SQRT1_2; }else av_assert0(0); } if(unaccounted & AV_CH_SIDE_LEFT){ if(out_ch_layout & AV_CH_BACK_LEFT){ /* if back channels do not exist in the input, just copy side channels to back channels, otherwise mix side into back */ if (in_ch_layout & AV_CH_BACK_LEFT) { matrix[BACK_LEFT ][SIDE_LEFT ] += M_SQRT1_2; matrix[BACK_RIGHT][SIDE_RIGHT] += M_SQRT1_2; } else { matrix[BACK_LEFT ][SIDE_LEFT ] += 1.0; matrix[BACK_RIGHT][SIDE_RIGHT] += 1.0; } }else if(out_ch_layout & AV_CH_BACK_CENTER){ matrix[BACK_CENTER][ SIDE_LEFT]+= M_SQRT1_2; matrix[BACK_CENTER][SIDE_RIGHT]+= M_SQRT1_2; }else if(out_ch_layout & AV_CH_FRONT_LEFT){ if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY) { matrix[FRONT_LEFT ][SIDE_LEFT ] -= surround_mix_level * M_SQRT1_2; matrix[FRONT_LEFT ][SIDE_RIGHT] -= surround_mix_level * M_SQRT1_2; matrix[FRONT_RIGHT][SIDE_LEFT ] += surround_mix_level * M_SQRT1_2; matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level * M_SQRT1_2; } else if (matrix_encoding == AV_MATRIX_ENCODING_DPLII) { matrix[FRONT_LEFT ][SIDE_LEFT ] -= surround_mix_level * SQRT3_2; matrix[FRONT_LEFT ][SIDE_RIGHT] -= surround_mix_level * M_SQRT1_2; matrix[FRONT_RIGHT][SIDE_LEFT ] += surround_mix_level * M_SQRT1_2; matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level * SQRT3_2; } else { matrix[ FRONT_LEFT][ SIDE_LEFT] += surround_mix_level; matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level; } }else if(out_ch_layout & AV_CH_FRONT_CENTER){ matrix[ FRONT_CENTER][SIDE_LEFT ]+= surround_mix_level * M_SQRT1_2; matrix[ FRONT_CENTER][SIDE_RIGHT]+= surround_mix_level * M_SQRT1_2; }else av_assert0(0); } if(unaccounted & AV_CH_FRONT_LEFT_OF_CENTER){ if(out_ch_layout & AV_CH_FRONT_LEFT){ matrix[ FRONT_LEFT][ FRONT_LEFT_OF_CENTER]+= 1.0; matrix[FRONT_RIGHT][FRONT_RIGHT_OF_CENTER]+= 1.0; }else if(out_ch_layout & AV_CH_FRONT_CENTER){ matrix[ FRONT_CENTER][ FRONT_LEFT_OF_CENTER]+= M_SQRT1_2; matrix[ FRONT_CENTER][FRONT_RIGHT_OF_CENTER]+= M_SQRT1_2; }else av_assert0(0); } /* mix LFE into front left/right or center */ if (unaccounted & AV_CH_LOW_FREQUENCY) { if (out_ch_layout & AV_CH_FRONT_CENTER) { matrix[FRONT_CENTER][LOW_FREQUENCY] += lfe_mix_level; } else if (out_ch_layout & AV_CH_FRONT_LEFT) { matrix[FRONT_LEFT ][LOW_FREQUENCY] += lfe_mix_level * M_SQRT1_2; matrix[FRONT_RIGHT][LOW_FREQUENCY] += lfe_mix_level * M_SQRT1_2; } else av_assert0(0); } for(out_i=i=0; i<64; i++){ double sum=0; int in_i=0; if((out_ch_layout & (1ULL<<i)) == 0) continue; for(j=0; j<64; j++){ if((in_ch_layout & (1ULL<<j)) == 0) continue; if (i < FF_ARRAY_ELEMS(matrix) && j < FF_ARRAY_ELEMS(matrix[0])) matrix_param[stride*out_i + in_i] = matrix[i][j]; else matrix_param[stride*out_i + in_i] = i == j && (in_ch_layout & out_ch_layout & (1ULL<<i)); sum += fabs(matrix_param[stride*out_i + in_i]); in_i++; } maxcoef= FFMAX(maxcoef, sum); out_i++; } if(rematrix_volume < 0) maxcoef = -rematrix_volume; if(maxcoef > maxval || rematrix_volume < 0){ maxcoef /= maxval; for(i=0; i<SWR_CH_MAX; i++) for(j=0; j<SWR_CH_MAX; j++){ matrix_param[stride*i + j] /= maxcoef; } } if(rematrix_volume > 0){ for(i=0; i<SWR_CH_MAX; i++) for(j=0; j<SWR_CH_MAX; j++){ matrix_param[stride*i + j] *= rematrix_volume; } } av_log(log_context, AV_LOG_DEBUG, "Matrix coefficients:\n"); for(i=0; i<av_get_channel_layout_nb_channels(out_ch_layout); i++){ const char *c = av_get_channel_name(av_channel_layout_extract_channel(out_ch_layout, i)); av_log(log_context, AV_LOG_DEBUG, "%s: ", c ? c : "?"); for(j=0; j<av_get_channel_layout_nb_channels(in_ch_layout); j++){ c = av_get_channel_name(av_channel_layout_extract_channel(in_ch_layout, j)); av_log(log_context, AV_LOG_DEBUG, "%s:%f ", c ? c : "?", matrix_param[stride*i + j]); } av_log(log_context, AV_LOG_DEBUG, "\n"); } return 0; }
av_cold static int auto_matrix(SwrContext *s) { int i, j, out_i; double matrix[NUM_NAMED_CHANNELS][NUM_NAMED_CHANNELS]={{0}}; int64_t unaccounted, in_ch_layout, out_ch_layout; double maxcoef=0; char buf[128]; const int matrix_encoding = s->matrix_encoding; float maxval; in_ch_layout = clean_layout(s, s->in_ch_layout); out_ch_layout = clean_layout(s, s->out_ch_layout); if( out_ch_layout == AV_CH_LAYOUT_STEREO_DOWNMIX && (in_ch_layout & AV_CH_LAYOUT_STEREO_DOWNMIX) == 0 ) out_ch_layout = AV_CH_LAYOUT_STEREO; if( in_ch_layout == AV_CH_LAYOUT_STEREO_DOWNMIX && (out_ch_layout & AV_CH_LAYOUT_STEREO_DOWNMIX) == 0 ) in_ch_layout = AV_CH_LAYOUT_STEREO; if(!sane_layout(in_ch_layout)){ av_get_channel_layout_string(buf, sizeof(buf), -1, s->in_ch_layout); av_log(s, AV_LOG_ERROR, "Input channel layout '%s' is not supported\n", buf); return AVERROR(EINVAL); } if(!sane_layout(out_ch_layout)){ av_get_channel_layout_string(buf, sizeof(buf), -1, s->out_ch_layout); av_log(s, AV_LOG_ERROR, "Output channel layout '%s' is not supported\n", buf); return AVERROR(EINVAL); } memset(s->matrix, 0, sizeof(s->matrix)); for(i=0; i<FF_ARRAY_ELEMS(matrix); i++){ if(in_ch_layout & out_ch_layout & (1ULL<<i)) matrix[i][i]= 1.0; } unaccounted= in_ch_layout & ~out_ch_layout; //FIXME implement dolby surround //FIXME implement full ac3 if(unaccounted & AV_CH_FRONT_CENTER){ if((out_ch_layout & AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO){ if(in_ch_layout & AV_CH_LAYOUT_STEREO) { matrix[ FRONT_LEFT][FRONT_CENTER]+= s->clev; matrix[FRONT_RIGHT][FRONT_CENTER]+= s->clev; } else { matrix[ FRONT_LEFT][FRONT_CENTER]+= M_SQRT1_2; matrix[FRONT_RIGHT][FRONT_CENTER]+= M_SQRT1_2; } }else av_assert0(0); } if(unaccounted & AV_CH_LAYOUT_STEREO){ if(out_ch_layout & AV_CH_FRONT_CENTER){ matrix[FRONT_CENTER][ FRONT_LEFT]+= M_SQRT1_2; matrix[FRONT_CENTER][FRONT_RIGHT]+= M_SQRT1_2; if(in_ch_layout & AV_CH_FRONT_CENTER) matrix[FRONT_CENTER][ FRONT_CENTER] = s->clev*sqrt(2); }else av_assert0(0); } if(unaccounted & AV_CH_BACK_CENTER){ if(out_ch_layout & AV_CH_BACK_LEFT){ matrix[ BACK_LEFT][BACK_CENTER]+= M_SQRT1_2; matrix[BACK_RIGHT][BACK_CENTER]+= M_SQRT1_2; }else if(out_ch_layout & AV_CH_SIDE_LEFT){ matrix[ SIDE_LEFT][BACK_CENTER]+= M_SQRT1_2; matrix[SIDE_RIGHT][BACK_CENTER]+= M_SQRT1_2; }else if(out_ch_layout & AV_CH_FRONT_LEFT){ if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY || matrix_encoding == AV_MATRIX_ENCODING_DPLII) { if (unaccounted & (AV_CH_BACK_LEFT | AV_CH_SIDE_LEFT)) { matrix[FRONT_LEFT ][BACK_CENTER] -= s->slev * M_SQRT1_2; matrix[FRONT_RIGHT][BACK_CENTER] += s->slev * M_SQRT1_2; } else { matrix[FRONT_LEFT ][BACK_CENTER] -= s->slev; matrix[FRONT_RIGHT][BACK_CENTER] += s->slev; } } else { matrix[ FRONT_LEFT][BACK_CENTER]+= s->slev*M_SQRT1_2; matrix[FRONT_RIGHT][BACK_CENTER]+= s->slev*M_SQRT1_2; } }else if(out_ch_layout & AV_CH_FRONT_CENTER){ matrix[ FRONT_CENTER][BACK_CENTER]+= s->slev*M_SQRT1_2; }else av_assert0(0); } if(unaccounted & AV_CH_BACK_LEFT){ if(out_ch_layout & AV_CH_BACK_CENTER){ matrix[BACK_CENTER][ BACK_LEFT]+= M_SQRT1_2; matrix[BACK_CENTER][BACK_RIGHT]+= M_SQRT1_2; }else if(out_ch_layout & AV_CH_SIDE_LEFT){ if(in_ch_layout & AV_CH_SIDE_LEFT){ matrix[ SIDE_LEFT][ BACK_LEFT]+= M_SQRT1_2; matrix[SIDE_RIGHT][BACK_RIGHT]+= M_SQRT1_2; }else{ matrix[ SIDE_LEFT][ BACK_LEFT]+= 1.0; matrix[SIDE_RIGHT][BACK_RIGHT]+= 1.0; } }else if(out_ch_layout & AV_CH_FRONT_LEFT){ if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY) { matrix[FRONT_LEFT ][BACK_LEFT ] -= s->slev * M_SQRT1_2; matrix[FRONT_LEFT ][BACK_RIGHT] -= s->slev * M_SQRT1_2; matrix[FRONT_RIGHT][BACK_LEFT ] += s->slev * M_SQRT1_2; matrix[FRONT_RIGHT][BACK_RIGHT] += s->slev * M_SQRT1_2; } else if (matrix_encoding == AV_MATRIX_ENCODING_DPLII) { matrix[FRONT_LEFT ][BACK_LEFT ] -= s->slev * SQRT3_2; matrix[FRONT_LEFT ][BACK_RIGHT] -= s->slev * M_SQRT1_2; matrix[FRONT_RIGHT][BACK_LEFT ] += s->slev * M_SQRT1_2; matrix[FRONT_RIGHT][BACK_RIGHT] += s->slev * SQRT3_2; } else { matrix[ FRONT_LEFT][ BACK_LEFT] += s->slev; matrix[FRONT_RIGHT][BACK_RIGHT] += s->slev; } }else if(out_ch_layout & AV_CH_FRONT_CENTER){ matrix[ FRONT_CENTER][BACK_LEFT ]+= s->slev*M_SQRT1_2; matrix[ FRONT_CENTER][BACK_RIGHT]+= s->slev*M_SQRT1_2; }else av_assert0(0); } if(unaccounted & AV_CH_SIDE_LEFT){ if(out_ch_layout & AV_CH_BACK_LEFT){ /* if back channels do not exist in the input, just copy side channels to back channels, otherwise mix side into back */ if (in_ch_layout & AV_CH_BACK_LEFT) { matrix[BACK_LEFT ][SIDE_LEFT ] += M_SQRT1_2; matrix[BACK_RIGHT][SIDE_RIGHT] += M_SQRT1_2; } else { matrix[BACK_LEFT ][SIDE_LEFT ] += 1.0; matrix[BACK_RIGHT][SIDE_RIGHT] += 1.0; } }else if(out_ch_layout & AV_CH_BACK_CENTER){ matrix[BACK_CENTER][ SIDE_LEFT]+= M_SQRT1_2; matrix[BACK_CENTER][SIDE_RIGHT]+= M_SQRT1_2; }else if(out_ch_layout & AV_CH_FRONT_LEFT){ if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY) { matrix[FRONT_LEFT ][SIDE_LEFT ] -= s->slev * M_SQRT1_2; matrix[FRONT_LEFT ][SIDE_RIGHT] -= s->slev * M_SQRT1_2; matrix[FRONT_RIGHT][SIDE_LEFT ] += s->slev * M_SQRT1_2; matrix[FRONT_RIGHT][SIDE_RIGHT] += s->slev * M_SQRT1_2; } else if (matrix_encoding == AV_MATRIX_ENCODING_DPLII) { matrix[FRONT_LEFT ][SIDE_LEFT ] -= s->slev * SQRT3_2; matrix[FRONT_LEFT ][SIDE_RIGHT] -= s->slev * M_SQRT1_2; matrix[FRONT_RIGHT][SIDE_LEFT ] += s->slev * M_SQRT1_2; matrix[FRONT_RIGHT][SIDE_RIGHT] += s->slev * SQRT3_2; } else { matrix[ FRONT_LEFT][ SIDE_LEFT] += s->slev; matrix[FRONT_RIGHT][SIDE_RIGHT] += s->slev; } }else if(out_ch_layout & AV_CH_FRONT_CENTER){ matrix[ FRONT_CENTER][SIDE_LEFT ]+= s->slev*M_SQRT1_2; matrix[ FRONT_CENTER][SIDE_RIGHT]+= s->slev*M_SQRT1_2; }else av_assert0(0); } if(unaccounted & AV_CH_FRONT_LEFT_OF_CENTER){ if(out_ch_layout & AV_CH_FRONT_LEFT){ matrix[ FRONT_LEFT][ FRONT_LEFT_OF_CENTER]+= 1.0; matrix[FRONT_RIGHT][FRONT_RIGHT_OF_CENTER]+= 1.0; }else if(out_ch_layout & AV_CH_FRONT_CENTER){ matrix[ FRONT_CENTER][ FRONT_LEFT_OF_CENTER]+= M_SQRT1_2; matrix[ FRONT_CENTER][FRONT_RIGHT_OF_CENTER]+= M_SQRT1_2; }else av_assert0(0); } /* mix LFE into front left/right or center */ if (unaccounted & AV_CH_LOW_FREQUENCY) { if (out_ch_layout & AV_CH_FRONT_CENTER) { matrix[FRONT_CENTER][LOW_FREQUENCY] += s->lfe_mix_level; } else if (out_ch_layout & AV_CH_FRONT_LEFT) { matrix[FRONT_LEFT ][LOW_FREQUENCY] += s->lfe_mix_level * M_SQRT1_2; matrix[FRONT_RIGHT][LOW_FREQUENCY] += s->lfe_mix_level * M_SQRT1_2; } else av_assert0(0); } for(out_i=i=0; i<64; i++){ double sum=0; int in_i=0; if((out_ch_layout & (1ULL<<i)) == 0) continue; for(j=0; j<64; j++){ if((in_ch_layout & (1ULL<<j)) == 0) continue; if (i < FF_ARRAY_ELEMS(matrix) && j < FF_ARRAY_ELEMS(matrix[0])) s->matrix[out_i][in_i]= matrix[i][j]; else s->matrix[out_i][in_i]= i == j && (in_ch_layout & out_ch_layout & (1ULL<<i)); sum += fabs(s->matrix[out_i][in_i]); in_i++; } maxcoef= FFMAX(maxcoef, sum); out_i++; } if(s->rematrix_volume < 0) maxcoef = -s->rematrix_volume; if (s->rematrix_maxval > 0) { maxval = s->rematrix_maxval; } else if ( av_get_packed_sample_fmt(s->out_sample_fmt) < AV_SAMPLE_FMT_FLT || av_get_packed_sample_fmt(s->int_sample_fmt) < AV_SAMPLE_FMT_FLT) { maxval = 1.0; } else maxval = INT_MAX; if(maxcoef > maxval || s->rematrix_volume < 0){ maxcoef /= maxval; for(i=0; i<SWR_CH_MAX; i++) for(j=0; j<SWR_CH_MAX; j++){ s->matrix[i][j] /= maxcoef; } } if(s->rematrix_volume > 0){ for(i=0; i<SWR_CH_MAX; i++) for(j=0; j<SWR_CH_MAX; j++){ s->matrix[i][j] *= s->rematrix_volume; } } av_log(s, AV_LOG_DEBUG, "Matrix coefficients:\n"); for(i=0; i<av_get_channel_layout_nb_channels(out_ch_layout); i++){ const char *c = av_get_channel_name(av_channel_layout_extract_channel(out_ch_layout, i)); av_log(s, AV_LOG_DEBUG, "%s: ", c ? c : "?"); for(j=0; j<av_get_channel_layout_nb_channels(in_ch_layout); j++){ c = av_get_channel_name(av_channel_layout_extract_channel(in_ch_layout, j)); av_log(s, AV_LOG_DEBUG, "%s:%f ", c ? c : "?", s->matrix[i][j]); } av_log(s, AV_LOG_DEBUG, "\n"); } return 0; }
static int auto_matrix(SwrContext *s) { int i, j, out_i; double matrix[64][64]={{0}}; int64_t unaccounted= s->in_ch_layout & ~s->out_ch_layout; double maxcoef=0; memset(s->matrix, 0, sizeof(s->matrix)); for(i=0; i<64; i++){ if(s->in_ch_layout & s->out_ch_layout & (1LL<<i)) matrix[i][i]= 1.0; } if(!sane_layout(s->in_ch_layout)){ av_log(s, AV_LOG_ERROR, "Input channel layout isnt supported\n"); return AVERROR(EINVAL); } if(!sane_layout(s->out_ch_layout)){ av_log(s, AV_LOG_ERROR, "Output channel layout isnt supported\n"); return AVERROR(EINVAL); } //FIXME implement dolby surround //FIXME implement full ac3 if(unaccounted & AV_CH_FRONT_CENTER){ if((s->out_ch_layout & AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO){ matrix[ FRONT_LEFT][FRONT_CENTER]+= M_SQRT1_2; matrix[FRONT_RIGHT][FRONT_CENTER]+= M_SQRT1_2; }else av_assert0(0); } if(unaccounted & AV_CH_LAYOUT_STEREO){ if(s->out_ch_layout & AV_CH_FRONT_CENTER){ matrix[FRONT_CENTER][ FRONT_LEFT]+= M_SQRT1_2; matrix[FRONT_CENTER][FRONT_RIGHT]+= M_SQRT1_2; if(s->in_ch_layout & AV_CH_FRONT_CENTER) matrix[FRONT_CENTER][ FRONT_CENTER] = s->clev*sqrt(2); }else av_assert0(0); } if(unaccounted & AV_CH_BACK_CENTER){ if(s->out_ch_layout & AV_CH_BACK_LEFT){ matrix[ BACK_LEFT][BACK_CENTER]+= M_SQRT1_2; matrix[BACK_RIGHT][BACK_CENTER]+= M_SQRT1_2; }else if(s->out_ch_layout & AV_CH_SIDE_LEFT){ matrix[ SIDE_LEFT][BACK_CENTER]+= M_SQRT1_2; matrix[SIDE_RIGHT][BACK_CENTER]+= M_SQRT1_2; }else if(s->out_ch_layout & AV_CH_FRONT_LEFT){ matrix[ FRONT_LEFT][BACK_CENTER]+= s->slev*M_SQRT1_2; matrix[FRONT_RIGHT][BACK_CENTER]+= s->slev*M_SQRT1_2; }else if(s->out_ch_layout & AV_CH_FRONT_CENTER){ matrix[ FRONT_CENTER][BACK_CENTER]+= s->slev*M_SQRT1_2; }else av_assert0(0); } if(unaccounted & AV_CH_BACK_LEFT){ if(s->out_ch_layout & AV_CH_BACK_CENTER){ matrix[BACK_CENTER][ BACK_LEFT]+= M_SQRT1_2; matrix[BACK_CENTER][BACK_RIGHT]+= M_SQRT1_2; }else if(s->out_ch_layout & AV_CH_SIDE_LEFT){ if(s->in_ch_layout & AV_CH_SIDE_LEFT){ matrix[ SIDE_LEFT][ BACK_LEFT]+= M_SQRT1_2; matrix[SIDE_RIGHT][BACK_RIGHT]+= M_SQRT1_2; }else{ matrix[ SIDE_LEFT][ BACK_LEFT]+= 1.0; matrix[SIDE_RIGHT][BACK_RIGHT]+= 1.0; } }else if(s->out_ch_layout & AV_CH_FRONT_LEFT){ matrix[ FRONT_LEFT][ BACK_LEFT]+= s->slev; matrix[FRONT_RIGHT][BACK_RIGHT]+= s->slev; }else if(s->out_ch_layout & AV_CH_FRONT_CENTER){ matrix[ FRONT_CENTER][BACK_LEFT ]+= s->slev*M_SQRT1_2; matrix[ FRONT_CENTER][BACK_RIGHT]+= s->slev*M_SQRT1_2; }else av_assert0(0); } if(unaccounted & AV_CH_SIDE_LEFT){ if(s->out_ch_layout & AV_CH_BACK_LEFT){ /* if back channels do not exist in the input, just copy side channels to back channels, otherwise mix side into back */ if (s->in_ch_layout & AV_CH_BACK_LEFT) { matrix[BACK_LEFT ][SIDE_LEFT ] += M_SQRT1_2; matrix[BACK_RIGHT][SIDE_RIGHT] += M_SQRT1_2; } else { matrix[BACK_LEFT ][SIDE_LEFT ] += 1.0; matrix[BACK_RIGHT][SIDE_RIGHT] += 1.0; } }else if(s->out_ch_layout & AV_CH_BACK_CENTER){ matrix[BACK_CENTER][ SIDE_LEFT]+= M_SQRT1_2; matrix[BACK_CENTER][SIDE_RIGHT]+= M_SQRT1_2; }else if(s->out_ch_layout & AV_CH_FRONT_LEFT){ matrix[ FRONT_LEFT][ SIDE_LEFT]+= s->slev; matrix[FRONT_RIGHT][SIDE_RIGHT]+= s->slev; }else if(s->out_ch_layout & AV_CH_FRONT_CENTER){ matrix[ FRONT_CENTER][SIDE_LEFT ]+= s->slev*M_SQRT1_2; matrix[ FRONT_CENTER][SIDE_RIGHT]+= s->slev*M_SQRT1_2; }else av_assert0(0); } if(unaccounted & AV_CH_FRONT_LEFT_OF_CENTER){ if(s->out_ch_layout & AV_CH_FRONT_LEFT){ matrix[ FRONT_LEFT][ FRONT_LEFT_OF_CENTER]+= 1.0; matrix[FRONT_RIGHT][FRONT_RIGHT_OF_CENTER]+= 1.0; }else if(s->out_ch_layout & AV_CH_FRONT_CENTER){ matrix[ FRONT_CENTER][ FRONT_LEFT_OF_CENTER]+= M_SQRT1_2; matrix[ FRONT_CENTER][FRONT_RIGHT_OF_CENTER]+= M_SQRT1_2; }else av_assert0(0); } /* mix LFE into front left/right or center */ if (unaccounted & AV_CH_LOW_FREQUENCY) { if (s->out_ch_layout & AV_CH_FRONT_CENTER) { matrix[FRONT_CENTER][LOW_FREQUENCY] += s->lfe_mix_level; } else if (s->out_ch_layout & AV_CH_FRONT_LEFT) { matrix[FRONT_LEFT ][LOW_FREQUENCY] += s->lfe_mix_level * M_SQRT1_2; matrix[FRONT_RIGHT][LOW_FREQUENCY] += s->lfe_mix_level * M_SQRT1_2; } else av_assert0(0); } for(out_i=i=0; i<64; i++){ double sum=0; int in_i=0; for(j=0; j<64; j++){ s->matrix[out_i][in_i]= matrix[i][j]; if(matrix[i][j]){ sum += fabs(matrix[i][j]); } if(s->in_ch_layout & (1ULL<<j)) in_i++; } maxcoef= FFMAX(maxcoef, sum); if(s->out_ch_layout & (1ULL<<i)) out_i++; } if(s->rematrix_volume < 0) maxcoef = -s->rematrix_volume; if(( av_get_packed_sample_fmt(s->out_sample_fmt) < AV_SAMPLE_FMT_FLT || av_get_packed_sample_fmt(s->int_sample_fmt) < AV_SAMPLE_FMT_FLT) && maxcoef > 1.0){ for(i=0; i<SWR_CH_MAX; i++) for(j=0; j<SWR_CH_MAX; j++){ s->matrix[i][j] /= maxcoef; } } if(s->rematrix_volume > 0){ for(i=0; i<SWR_CH_MAX; i++) for(j=0; j<SWR_CH_MAX; j++){ s->matrix[i][j] *= s->rematrix_volume; } } for(i=0; i<av_get_channel_layout_nb_channels(s->out_ch_layout); i++){ for(j=0; j<av_get_channel_layout_nb_channels(s->in_ch_layout); j++){ av_log(NULL, AV_LOG_DEBUG, "%f ", s->matrix[i][j]); } av_log(NULL, AV_LOG_DEBUG, "\n"); } return 0; }
int swr_rematrix_init(SwrContext *s){ int i, j, out_i; double matrix[64][64]={{0}}; int64_t unaccounted= s->in_ch_layout & ~s->out_ch_layout; double maxcoef=0; for(i=0; i<64; i++){ if(s->in_ch_layout & s->out_ch_layout & (1LL<<i)) matrix[i][i]= 1.0; } if(!sane_layout(s->in_ch_layout)){ av_log(s, AV_LOG_ERROR, "Input channel layout isnt supported\n"); return AVERROR(EINVAL); } if(!sane_layout(s->out_ch_layout)){ av_log(s, AV_LOG_ERROR, "Output channel layout isnt supported\n"); return AVERROR(EINVAL); } //FIXME implement dolby surround //FIXME implement full ac3 if(unaccounted & AV_CH_FRONT_CENTER){ if((s->out_ch_layout & AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO){ matrix[ FRONT_LEFT][FRONT_CENTER]+= M_SQRT1_2; matrix[FRONT_RIGHT][FRONT_CENTER]+= M_SQRT1_2; }else av_assert0(0); } if(unaccounted & AV_CH_LAYOUT_STEREO){ if(s->out_ch_layout & AV_CH_FRONT_CENTER){ matrix[FRONT_CENTER][ FRONT_LEFT]+= M_SQRT1_2; matrix[FRONT_CENTER][FRONT_RIGHT]+= M_SQRT1_2; if(s->in_ch_layout & AV_CH_FRONT_CENTER) matrix[FRONT_CENTER][ FRONT_CENTER] = s->clev*sqrt(2); }else av_assert0(0); } if(unaccounted & AV_CH_BACK_CENTER){ if(s->out_ch_layout & AV_CH_BACK_LEFT){ matrix[ BACK_LEFT][BACK_CENTER]+= M_SQRT1_2; matrix[BACK_RIGHT][BACK_CENTER]+= M_SQRT1_2; }else if(s->out_ch_layout & AV_CH_SIDE_LEFT){ matrix[ SIDE_LEFT][BACK_CENTER]+= M_SQRT1_2; matrix[SIDE_RIGHT][BACK_CENTER]+= M_SQRT1_2; }else if(s->out_ch_layout & AV_CH_FRONT_LEFT){ matrix[ FRONT_LEFT][BACK_CENTER]+= s->slev*M_SQRT1_2; matrix[FRONT_RIGHT][BACK_CENTER]+= s->slev*M_SQRT1_2; }else if(s->out_ch_layout & AV_CH_FRONT_CENTER){ matrix[ FRONT_CENTER][BACK_CENTER]+= s->slev*M_SQRT1_2; }else av_assert0(0); } if(unaccounted & AV_CH_BACK_LEFT){ if(s->out_ch_layout & AV_CH_BACK_CENTER){ matrix[BACK_CENTER][ BACK_LEFT]+= M_SQRT1_2; matrix[BACK_CENTER][BACK_RIGHT]+= M_SQRT1_2; }else if(s->out_ch_layout & AV_CH_SIDE_LEFT){ if(s->in_ch_layout & AV_CH_SIDE_LEFT){ matrix[ SIDE_LEFT][ BACK_LEFT]+= M_SQRT1_2; matrix[SIDE_RIGHT][BACK_RIGHT]+= M_SQRT1_2; }else{ matrix[ SIDE_LEFT][ BACK_LEFT]+= 1.0; matrix[SIDE_RIGHT][BACK_RIGHT]+= 1.0; } }else if(s->out_ch_layout & AV_CH_FRONT_LEFT){ matrix[ FRONT_LEFT][ BACK_LEFT]+= s->slev; matrix[FRONT_RIGHT][BACK_RIGHT]+= s->slev; }else if(s->out_ch_layout & AV_CH_FRONT_CENTER){ matrix[ FRONT_CENTER][BACK_LEFT ]+= s->slev*M_SQRT1_2; matrix[ FRONT_CENTER][BACK_RIGHT]+= s->slev*M_SQRT1_2; }else av_assert0(0); } if(unaccounted & AV_CH_SIDE_LEFT){ if(s->out_ch_layout & AV_CH_BACK_LEFT){ matrix[ BACK_LEFT][ SIDE_LEFT]+= 1.0; matrix[BACK_RIGHT][SIDE_RIGHT]+= 1.0; }else if(s->out_ch_layout & AV_CH_BACK_CENTER){ matrix[BACK_CENTER][ SIDE_LEFT]+= M_SQRT1_2; matrix[BACK_CENTER][SIDE_RIGHT]+= M_SQRT1_2; }else if(s->out_ch_layout & AV_CH_FRONT_LEFT){ matrix[ FRONT_LEFT][ SIDE_LEFT]+= s->slev; matrix[FRONT_RIGHT][SIDE_RIGHT]+= s->slev; }else if(s->out_ch_layout & AV_CH_FRONT_CENTER){ matrix[ FRONT_CENTER][SIDE_LEFT ]+= s->slev*M_SQRT1_2; matrix[ FRONT_CENTER][SIDE_RIGHT]+= s->slev*M_SQRT1_2; }else av_assert0(0); } if(unaccounted & AV_CH_FRONT_LEFT_OF_CENTER){ if(s->out_ch_layout & AV_CH_FRONT_LEFT){ matrix[ FRONT_LEFT][ FRONT_LEFT_OF_CENTER]+= 1.0; matrix[FRONT_RIGHT][FRONT_RIGHT_OF_CENTER]+= 1.0; }else if(s->out_ch_layout & AV_CH_FRONT_CENTER){ matrix[ FRONT_CENTER][ FRONT_LEFT_OF_CENTER]+= M_SQRT1_2; matrix[ FRONT_CENTER][FRONT_RIGHT_OF_CENTER]+= M_SQRT1_2; }else av_assert0(0); } //FIXME quantize for integeres for(out_i=i=0; i<64; i++){ double sum=0; int in_i=0; int ch_in=0; for(j=0; j<64; j++){ s->matrix[out_i][in_i]= matrix[i][j]; s->matrix16[out_i][in_i]= lrintf(matrix[i][j] * 32768); if(matrix[i][j]){ s->matrix_ch[out_i][++ch_in]= in_i; sum += fabs(matrix[i][j]); } if(s->in_ch_layout & (1ULL<<j)) in_i++; } s->matrix_ch[out_i][0]= ch_in; maxcoef= FFMAX(maxcoef, sum); if(s->out_ch_layout & (1ULL<<i)) out_i++; } if(( s->out_sample_fmt < AV_SAMPLE_FMT_FLT || s->int_sample_fmt < AV_SAMPLE_FMT_FLT) && maxcoef > 1.0){ for(i=0; i<SWR_CH_MAX; i++) for(j=0; j<SWR_CH_MAX; j++){ s->matrix[i][j] /= maxcoef; s->matrix16[i][j]= lrintf(s->matrix[i][j] * 32768); } } for(i=0; i<av_get_channel_layout_nb_channels(s->out_ch_layout); i++){ for(j=0; j<av_get_channel_layout_nb_channels(s->in_ch_layout); j++){ av_log(NULL, AV_LOG_DEBUG, "%f ", s->matrix[i][j]); } av_log(NULL, AV_LOG_DEBUG, "\n"); } return 0; }
int avresample_build_matrix(uint64_t in_layout, uint64_t out_layout, double center_mix_level, double surround_mix_level, double lfe_mix_level, int normalize, double *matrix_out, int stride, enum AVMatrixEncoding matrix_encoding) { int i, j, out_i, out_j; double matrix[64][64] = {{0}}; int64_t unaccounted; double maxcoef = 0; int in_channels, out_channels; if ((out_layout & AV_CH_LAYOUT_STEREO_DOWNMIX) == AV_CH_LAYOUT_STEREO_DOWNMIX) { out_layout = AV_CH_LAYOUT_STEREO; } unaccounted = in_layout & ~out_layout; in_channels = av_get_channel_layout_nb_channels( in_layout); out_channels = av_get_channel_layout_nb_channels(out_layout); memset(matrix_out, 0, out_channels * stride * sizeof(*matrix_out)); /* check if layouts are supported */ if (!in_layout || in_channels > AVRESAMPLE_MAX_CHANNELS) return AVERROR(EINVAL); if (!out_layout || out_channels > AVRESAMPLE_MAX_CHANNELS) return AVERROR(EINVAL); /* check if layouts are unbalanced or abnormal */ if (!sane_layout(in_layout) || !sane_layout(out_layout)) return AVERROR_PATCHWELCOME; /* route matching input/output channels */ for (i = 0; i < 64; i++) { if (in_layout & out_layout & (1ULL << i)) matrix[i][i] = 1.0; } /* mix front center to front left/right */ if (unaccounted & AV_CH_FRONT_CENTER) { if ((out_layout & AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO) { matrix[FRONT_LEFT ][FRONT_CENTER] += center_mix_level * M_SQRT1_2; matrix[FRONT_RIGHT][FRONT_CENTER] += center_mix_level * M_SQRT1_2; } else return AVERROR_PATCHWELCOME; } /* mix front left/right to center */ if (unaccounted & AV_CH_LAYOUT_STEREO) { if (out_layout & AV_CH_FRONT_CENTER) { matrix[FRONT_CENTER][FRONT_LEFT ] += M_SQRT1_2; matrix[FRONT_CENTER][FRONT_RIGHT] += M_SQRT1_2; /* mix left/right/center to center */ if (in_layout & AV_CH_FRONT_CENTER) matrix[FRONT_CENTER][FRONT_CENTER] = center_mix_level * M_SQRT2; } else return AVERROR_PATCHWELCOME; } /* mix back center to back, side, or front */ if (unaccounted & AV_CH_BACK_CENTER) { if (out_layout & AV_CH_BACK_LEFT) { matrix[BACK_LEFT ][BACK_CENTER] += M_SQRT1_2; matrix[BACK_RIGHT][BACK_CENTER] += M_SQRT1_2; } else if (out_layout & AV_CH_SIDE_LEFT) { matrix[SIDE_LEFT ][BACK_CENTER] += M_SQRT1_2; matrix[SIDE_RIGHT][BACK_CENTER] += M_SQRT1_2; } else if (out_layout & AV_CH_FRONT_LEFT) { if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY || matrix_encoding == AV_MATRIX_ENCODING_DPLII) { if (unaccounted & (AV_CH_BACK_LEFT | AV_CH_SIDE_LEFT)) { matrix[FRONT_LEFT ][BACK_CENTER] -= surround_mix_level * M_SQRT1_2; matrix[FRONT_RIGHT][BACK_CENTER] += surround_mix_level * M_SQRT1_2; } else { matrix[FRONT_LEFT ][BACK_CENTER] -= surround_mix_level; matrix[FRONT_RIGHT][BACK_CENTER] += surround_mix_level; } } else { matrix[FRONT_LEFT ][BACK_CENTER] += surround_mix_level * M_SQRT1_2; matrix[FRONT_RIGHT][BACK_CENTER] += surround_mix_level * M_SQRT1_2; } } else if (out_layout & AV_CH_FRONT_CENTER) { matrix[FRONT_CENTER][BACK_CENTER] += surround_mix_level * M_SQRT1_2; } else return AVERROR_PATCHWELCOME; } /* mix back left/right to back center, side, or front */ if (unaccounted & AV_CH_BACK_LEFT) { if (out_layout & AV_CH_BACK_CENTER) { matrix[BACK_CENTER][BACK_LEFT ] += M_SQRT1_2; matrix[BACK_CENTER][BACK_RIGHT] += M_SQRT1_2; } else if (out_layout & AV_CH_SIDE_LEFT) { /* if side channels do not exist in the input, just copy back channels to side channels, otherwise mix back into side */ if (in_layout & AV_CH_SIDE_LEFT) { matrix[SIDE_LEFT ][BACK_LEFT ] += M_SQRT1_2; matrix[SIDE_RIGHT][BACK_RIGHT] += M_SQRT1_2; } else { matrix[SIDE_LEFT ][BACK_LEFT ] += 1.0; matrix[SIDE_RIGHT][BACK_RIGHT] += 1.0; } } else if (out_layout & AV_CH_FRONT_LEFT) { if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY) { matrix[FRONT_LEFT ][BACK_LEFT ] -= surround_mix_level * M_SQRT1_2; matrix[FRONT_LEFT ][BACK_RIGHT] -= surround_mix_level * M_SQRT1_2; matrix[FRONT_RIGHT][BACK_LEFT ] += surround_mix_level * M_SQRT1_2; matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level * M_SQRT1_2; } else if (matrix_encoding == AV_MATRIX_ENCODING_DPLII) { matrix[FRONT_LEFT ][BACK_LEFT ] -= surround_mix_level * SQRT3_2; matrix[FRONT_LEFT ][BACK_RIGHT] -= surround_mix_level * M_SQRT1_2; matrix[FRONT_RIGHT][BACK_LEFT ] += surround_mix_level * M_SQRT1_2; matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level * SQRT3_2; } else { matrix[FRONT_LEFT ][BACK_LEFT ] += surround_mix_level; matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level; } } else if (out_layout & AV_CH_FRONT_CENTER) { matrix[FRONT_CENTER][BACK_LEFT ] += surround_mix_level * M_SQRT1_2; matrix[FRONT_CENTER][BACK_RIGHT] += surround_mix_level * M_SQRT1_2; } else return AVERROR_PATCHWELCOME; } /* mix side left/right into back or front */ if (unaccounted & AV_CH_SIDE_LEFT) { if (out_layout & AV_CH_BACK_LEFT) { /* if back channels do not exist in the input, just copy side channels to back channels, otherwise mix side into back */ if (in_layout & AV_CH_BACK_LEFT) { matrix[BACK_LEFT ][SIDE_LEFT ] += M_SQRT1_2; matrix[BACK_RIGHT][SIDE_RIGHT] += M_SQRT1_2; } else { matrix[BACK_LEFT ][SIDE_LEFT ] += 1.0; matrix[BACK_RIGHT][SIDE_RIGHT] += 1.0; } } else if (out_layout & AV_CH_BACK_CENTER) { matrix[BACK_CENTER][SIDE_LEFT ] += M_SQRT1_2; matrix[BACK_CENTER][SIDE_RIGHT] += M_SQRT1_2; } else if (out_layout & AV_CH_FRONT_LEFT) { if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY) { matrix[FRONT_LEFT ][SIDE_LEFT ] -= surround_mix_level * M_SQRT1_2; matrix[FRONT_LEFT ][SIDE_RIGHT] -= surround_mix_level * M_SQRT1_2; matrix[FRONT_RIGHT][SIDE_LEFT ] += surround_mix_level * M_SQRT1_2; matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level * M_SQRT1_2; } else if (matrix_encoding == AV_MATRIX_ENCODING_DPLII) { matrix[FRONT_LEFT ][SIDE_LEFT ] -= surround_mix_level * SQRT3_2; matrix[FRONT_LEFT ][SIDE_RIGHT] -= surround_mix_level * M_SQRT1_2; matrix[FRONT_RIGHT][SIDE_LEFT ] += surround_mix_level * M_SQRT1_2; matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level * SQRT3_2; } else { matrix[FRONT_LEFT ][SIDE_LEFT ] += surround_mix_level; matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level; } } else if (out_layout & AV_CH_FRONT_CENTER) { matrix[FRONT_CENTER][SIDE_LEFT ] += surround_mix_level * M_SQRT1_2; matrix[FRONT_CENTER][SIDE_RIGHT] += surround_mix_level * M_SQRT1_2; } else return AVERROR_PATCHWELCOME; } /* mix left-of-center/right-of-center into front left/right or center */ if (unaccounted & AV_CH_FRONT_LEFT_OF_CENTER) { if (out_layout & AV_CH_FRONT_LEFT) { matrix[FRONT_LEFT ][FRONT_LEFT_OF_CENTER ] += 1.0; matrix[FRONT_RIGHT][FRONT_RIGHT_OF_CENTER] += 1.0; } else if (out_layout & AV_CH_FRONT_CENTER) { matrix[FRONT_CENTER][FRONT_LEFT_OF_CENTER ] += M_SQRT1_2; matrix[FRONT_CENTER][FRONT_RIGHT_OF_CENTER] += M_SQRT1_2; } else return AVERROR_PATCHWELCOME; } /* mix LFE into front left/right or center */ if (unaccounted & AV_CH_LOW_FREQUENCY) { if (out_layout & AV_CH_FRONT_CENTER) { matrix[FRONT_CENTER][LOW_FREQUENCY] += lfe_mix_level; } else if (out_layout & AV_CH_FRONT_LEFT) { matrix[FRONT_LEFT ][LOW_FREQUENCY] += lfe_mix_level * M_SQRT1_2; matrix[FRONT_RIGHT][LOW_FREQUENCY] += lfe_mix_level * M_SQRT1_2; } else return AVERROR_PATCHWELCOME; } /* transfer internal matrix to output matrix and calculate maximum per-channel coefficient sum */ for (out_i = i = 0; out_i < out_channels && i < 64; i++) { double sum = 0; for (out_j = j = 0; out_j < in_channels && j < 64; j++) { matrix_out[out_i * stride + out_j] = matrix[i][j]; sum += fabs(matrix[i][j]); if (in_layout & (1ULL << j)) out_j++; } maxcoef = FFMAX(maxcoef, sum); if (out_layout & (1ULL << i)) out_i++; } /* normalize */ if (normalize && maxcoef > 1.0) { for (i = 0; i < out_channels; i++) for (j = 0; j < in_channels; j++) matrix_out[i * stride + j] /= maxcoef; } return 0; }