mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
Merge commit '14758e3211d34a97c42b07acae117ce5627d7f57'
* commit '14758e3211d34a97c42b07acae117ce5627d7f57': lavr: temporarily store custom matrix in AVAudioResampleContext lavr: clarify documentation for avresample_get/set_matrix() Merged-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
commit
82c0211213
@ -302,27 +302,37 @@ static int mix_function_init(AudioMix *am)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ff_audio_mix_init(AVAudioResampleContext *avr)
|
AudioMix *ff_audio_mix_alloc(AVAudioResampleContext *avr)
|
||||||
{
|
{
|
||||||
|
AudioMix *am;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
am = av_mallocz(sizeof(*am));
|
||||||
|
if (!am)
|
||||||
|
return NULL;
|
||||||
|
am->avr = avr;
|
||||||
|
|
||||||
if (avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P &&
|
if (avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P &&
|
||||||
avr->internal_sample_fmt != AV_SAMPLE_FMT_FLTP) {
|
avr->internal_sample_fmt != AV_SAMPLE_FMT_FLTP) {
|
||||||
av_log(avr, AV_LOG_ERROR, "Unsupported internal format for "
|
av_log(avr, AV_LOG_ERROR, "Unsupported internal format for "
|
||||||
"mixing: %s\n",
|
"mixing: %s\n",
|
||||||
av_get_sample_fmt_name(avr->internal_sample_fmt));
|
av_get_sample_fmt_name(avr->internal_sample_fmt));
|
||||||
return AVERROR(EINVAL);
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
am->fmt = avr->internal_sample_fmt;
|
||||||
|
am->coeff_type = avr->mix_coeff_type;
|
||||||
|
am->in_layout = avr->in_channel_layout;
|
||||||
|
am->out_layout = avr->out_channel_layout;
|
||||||
|
am->in_channels = avr->in_channels;
|
||||||
|
am->out_channels = avr->out_channels;
|
||||||
|
|
||||||
/* build matrix if the user did not already set one */
|
/* build matrix if the user did not already set one */
|
||||||
if (avr->am->matrix) {
|
if (avr->mix_matrix) {
|
||||||
if (avr->am->coeff_type != avr->mix_coeff_type ||
|
ret = ff_audio_mix_set_matrix(am, avr->mix_matrix, avr->in_channels);
|
||||||
avr->am->in_layout != avr->in_channel_layout ||
|
if (ret < 0)
|
||||||
avr->am->out_layout != avr->out_channel_layout) {
|
goto error;
|
||||||
av_log(avr, AV_LOG_ERROR,
|
av_freep(&avr->mix_matrix);
|
||||||
"Custom matrix does not match current parameters\n");
|
|
||||||
return AVERROR(EINVAL);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
int i, j;
|
int i, j;
|
||||||
char in_layout_name[128];
|
char in_layout_name[128];
|
||||||
@ -330,7 +340,7 @@ int ff_audio_mix_init(AVAudioResampleContext *avr)
|
|||||||
double *matrix_dbl = av_mallocz(avr->out_channels * avr->in_channels *
|
double *matrix_dbl = av_mallocz(avr->out_channels * avr->in_channels *
|
||||||
sizeof(*matrix_dbl));
|
sizeof(*matrix_dbl));
|
||||||
if (!matrix_dbl)
|
if (!matrix_dbl)
|
||||||
return AVERROR(ENOMEM);
|
goto error;
|
||||||
|
|
||||||
ret = avresample_build_matrix(avr->in_channel_layout,
|
ret = avresample_build_matrix(avr->in_channel_layout,
|
||||||
avr->out_channel_layout,
|
avr->out_channel_layout,
|
||||||
@ -343,7 +353,7 @@ int ff_audio_mix_init(AVAudioResampleContext *avr)
|
|||||||
avr->matrix_encoding);
|
avr->matrix_encoding);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
av_free(matrix_dbl);
|
av_free(matrix_dbl);
|
||||||
return ret;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
av_get_channel_layout_string(in_layout_name, sizeof(in_layout_name),
|
av_get_channel_layout_string(in_layout_name, sizeof(in_layout_name),
|
||||||
@ -360,32 +370,33 @@ int ff_audio_mix_init(AVAudioResampleContext *avr)
|
|||||||
av_log(avr, AV_LOG_DEBUG, "\n");
|
av_log(avr, AV_LOG_DEBUG, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = avresample_set_matrix(avr, matrix_dbl, avr->in_channels);
|
ret = ff_audio_mix_set_matrix(am, matrix_dbl, avr->in_channels);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
av_free(matrix_dbl);
|
av_free(matrix_dbl);
|
||||||
return ret;
|
goto error;
|
||||||
}
|
}
|
||||||
av_free(matrix_dbl);
|
av_free(matrix_dbl);
|
||||||
}
|
}
|
||||||
|
|
||||||
avr->am->fmt = avr->internal_sample_fmt;
|
ret = mix_function_init(am);
|
||||||
avr->am->coeff_type = avr->mix_coeff_type;
|
|
||||||
avr->am->in_layout = avr->in_channel_layout;
|
|
||||||
avr->am->out_layout = avr->out_channel_layout;
|
|
||||||
avr->am->in_channels = avr->in_channels;
|
|
||||||
avr->am->out_channels = avr->out_channels;
|
|
||||||
|
|
||||||
ret = mix_function_init(avr->am);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
goto error;
|
||||||
|
|
||||||
return 0;
|
return am;
|
||||||
|
|
||||||
|
error:
|
||||||
|
av_free(am);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ff_audio_mix_close(AudioMix *am)
|
void ff_audio_mix_free(AudioMix **am_p)
|
||||||
{
|
{
|
||||||
if (!am)
|
AudioMix *am;
|
||||||
|
|
||||||
|
if (!*am_p)
|
||||||
return;
|
return;
|
||||||
|
am = *am_p;
|
||||||
|
|
||||||
if (am->matrix) {
|
if (am->matrix) {
|
||||||
av_free(am->matrix[0]);
|
av_free(am->matrix[0]);
|
||||||
am->matrix = NULL;
|
am->matrix = NULL;
|
||||||
@ -393,6 +404,8 @@ void ff_audio_mix_close(AudioMix *am)
|
|||||||
memset(am->matrix_q8, 0, sizeof(am->matrix_q8 ));
|
memset(am->matrix_q8, 0, sizeof(am->matrix_q8 ));
|
||||||
memset(am->matrix_q15, 0, sizeof(am->matrix_q15));
|
memset(am->matrix_q15, 0, sizeof(am->matrix_q15));
|
||||||
memset(am->matrix_flt, 0, sizeof(am->matrix_flt));
|
memset(am->matrix_flt, 0, sizeof(am->matrix_flt));
|
||||||
|
|
||||||
|
av_freep(am_p);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ff_audio_mix(AudioMix *am, AudioData *src)
|
int ff_audio_mix(AudioMix *am, AudioData *src)
|
||||||
@ -424,3 +437,92 @@ int ff_audio_mix(AudioMix *am, AudioData *src)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ff_audio_mix_get_matrix(AudioMix *am, double *matrix, int stride)
|
||||||
|
{
|
||||||
|
int i, o;
|
||||||
|
|
||||||
|
if ( am->in_channels <= 0 || am->in_channels > AVRESAMPLE_MAX_CHANNELS ||
|
||||||
|
am->out_channels <= 0 || am->out_channels > AVRESAMPLE_MAX_CHANNELS) {
|
||||||
|
av_log(am, AV_LOG_ERROR, "Invalid channel counts\n");
|
||||||
|
return AVERROR(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GET_MATRIX_CONVERT(suffix, scale) \
|
||||||
|
if (!am->matrix_ ## suffix[0]) { \
|
||||||
|
av_log(am, AV_LOG_ERROR, "matrix is not set\n"); \
|
||||||
|
return AVERROR(EINVAL); \
|
||||||
|
} \
|
||||||
|
for (o = 0; o < am->out_channels; o++) \
|
||||||
|
for (i = 0; i < am->in_channels; i++) \
|
||||||
|
matrix[o * stride + i] = am->matrix_ ## suffix[o][i] * (scale);
|
||||||
|
|
||||||
|
switch (am->coeff_type) {
|
||||||
|
case AV_MIX_COEFF_TYPE_Q8:
|
||||||
|
GET_MATRIX_CONVERT(q8, 1.0 / 256.0);
|
||||||
|
break;
|
||||||
|
case AV_MIX_COEFF_TYPE_Q15:
|
||||||
|
GET_MATRIX_CONVERT(q15, 1.0 / 32768.0);
|
||||||
|
break;
|
||||||
|
case AV_MIX_COEFF_TYPE_FLT:
|
||||||
|
GET_MATRIX_CONVERT(flt, 1.0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
av_log(am, AV_LOG_ERROR, "Invalid mix coeff type\n");
|
||||||
|
return AVERROR(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ff_audio_mix_set_matrix(AudioMix *am, const double *matrix, int stride)
|
||||||
|
{
|
||||||
|
int i, o;
|
||||||
|
|
||||||
|
if ( am->in_channels <= 0 || am->in_channels > AVRESAMPLE_MAX_CHANNELS ||
|
||||||
|
am->out_channels <= 0 || am->out_channels > AVRESAMPLE_MAX_CHANNELS) {
|
||||||
|
av_log(am, AV_LOG_ERROR, "Invalid channel counts\n");
|
||||||
|
return AVERROR(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (am->matrix) {
|
||||||
|
av_free(am->matrix[0]);
|
||||||
|
am->matrix = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CONVERT_MATRIX(type, expr) \
|
||||||
|
am->matrix_## type[0] = av_mallocz(am->out_channels * am->in_channels * \
|
||||||
|
sizeof(*am->matrix_## type[0])); \
|
||||||
|
if (!am->matrix_## type[0]) \
|
||||||
|
return AVERROR(ENOMEM); \
|
||||||
|
for (o = 0; o < am->out_channels; o++) { \
|
||||||
|
if (o > 0) \
|
||||||
|
am->matrix_## type[o] = am->matrix_## type[o - 1] + \
|
||||||
|
am->in_channels; \
|
||||||
|
for (i = 0; i < am->in_channels; i++) { \
|
||||||
|
double v = matrix[o * stride + i]; \
|
||||||
|
am->matrix_## type[o][i] = expr; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
am->matrix = (void **)am->matrix_## type;
|
||||||
|
|
||||||
|
switch (am->coeff_type) {
|
||||||
|
case AV_MIX_COEFF_TYPE_Q8:
|
||||||
|
CONVERT_MATRIX(q8, av_clip_int16(lrint(256.0 * v)))
|
||||||
|
break;
|
||||||
|
case AV_MIX_COEFF_TYPE_Q15:
|
||||||
|
CONVERT_MATRIX(q15, av_clipl_int32(llrint(32768.0 * v)))
|
||||||
|
break;
|
||||||
|
case AV_MIX_COEFF_TYPE_FLT:
|
||||||
|
CONVERT_MATRIX(flt, v)
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
av_log(am, AV_LOG_ERROR, "Invalid mix coeff type\n");
|
||||||
|
return AVERROR(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: detect situations where we can just swap around pointers
|
||||||
|
instead of doing matrix multiplications with 0.0 and 1.0 */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -79,28 +79,36 @@ void ff_audio_mix_set_func(AudioMix *am, enum AVSampleFormat fmt,
|
|||||||
const char *descr, void *mix_func);
|
const char *descr, void *mix_func);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the AudioMix context in the AVAudioResampleContext.
|
* Allocate and initialize an AudioMix context.
|
||||||
*
|
*
|
||||||
* The parameters in the AVAudioResampleContext are used to initialize the
|
* The parameters in the AVAudioResampleContext are used to initialize the
|
||||||
* AudioMix context and set the mixing matrix.
|
* AudioMix context.
|
||||||
*
|
*
|
||||||
* @param avr AVAudioResampleContext
|
* @param avr AVAudioResampleContext
|
||||||
* @return 0 on success, negative AVERROR code on failure
|
* @return newly-allocated AudioMix context.
|
||||||
*/
|
*/
|
||||||
int ff_audio_mix_init(AVAudioResampleContext *avr);
|
AudioMix *ff_audio_mix_alloc(AVAudioResampleContext *avr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close an AudioMix context.
|
* Free an AudioMix context.
|
||||||
*
|
|
||||||
* This clears and frees the mixing matrix arrays.
|
|
||||||
*/
|
*/
|
||||||
void ff_audio_mix_close(AudioMix *am);
|
void ff_audio_mix_free(AudioMix **am);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply channel mixing to audio data using the current mixing matrix.
|
* Apply channel mixing to audio data using the current mixing matrix.
|
||||||
*/
|
*/
|
||||||
int ff_audio_mix(AudioMix *am, AudioData *src);
|
int ff_audio_mix(AudioMix *am, AudioData *src);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current mixing matrix.
|
||||||
|
*/
|
||||||
|
int ff_audio_mix_get_matrix(AudioMix *am, double *matrix, int stride);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current mixing matrix.
|
||||||
|
*/
|
||||||
|
int ff_audio_mix_set_matrix(AudioMix *am, const double *matrix, int stride);
|
||||||
|
|
||||||
/* arch-specific initialization functions */
|
/* arch-specific initialization functions */
|
||||||
|
|
||||||
void ff_audio_mix_init_x86(AudioMix *am);
|
void ff_audio_mix_init_x86(AudioMix *am);
|
||||||
|
@ -287,115 +287,3 @@ int avresample_build_matrix(uint64_t in_layout, uint64_t out_layout,
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix,
|
|
||||||
int stride)
|
|
||||||
{
|
|
||||||
int in_channels, out_channels, i, o;
|
|
||||||
|
|
||||||
in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout);
|
|
||||||
out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout);
|
|
||||||
|
|
||||||
if ( in_channels <= 0 || in_channels > AVRESAMPLE_MAX_CHANNELS ||
|
|
||||||
out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) {
|
|
||||||
av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n");
|
|
||||||
return AVERROR(EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (avr->mix_coeff_type) {
|
|
||||||
case AV_MIX_COEFF_TYPE_Q8:
|
|
||||||
if (!avr->am->matrix_q8[0]) {
|
|
||||||
av_log(avr, AV_LOG_ERROR, "matrix is not set\n");
|
|
||||||
return AVERROR(EINVAL);
|
|
||||||
}
|
|
||||||
for (o = 0; o < out_channels; o++)
|
|
||||||
for (i = 0; i < in_channels; i++)
|
|
||||||
matrix[o * stride + i] = avr->am->matrix_q8[o][i] / 256.0;
|
|
||||||
break;
|
|
||||||
case AV_MIX_COEFF_TYPE_Q15:
|
|
||||||
if (!avr->am->matrix_q15[0]) {
|
|
||||||
av_log(avr, AV_LOG_ERROR, "matrix is not set\n");
|
|
||||||
return AVERROR(EINVAL);
|
|
||||||
}
|
|
||||||
for (o = 0; o < out_channels; o++)
|
|
||||||
for (i = 0; i < in_channels; i++)
|
|
||||||
matrix[o * stride + i] = avr->am->matrix_q15[o][i] / 32768.0;
|
|
||||||
break;
|
|
||||||
case AV_MIX_COEFF_TYPE_FLT:
|
|
||||||
if (!avr->am->matrix_flt[0]) {
|
|
||||||
av_log(avr, AV_LOG_ERROR, "matrix is not set\n");
|
|
||||||
return AVERROR(EINVAL);
|
|
||||||
}
|
|
||||||
for (o = 0; o < out_channels; o++)
|
|
||||||
for (i = 0; i < in_channels; i++)
|
|
||||||
matrix[o * stride + i] = avr->am->matrix_flt[o][i];
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
av_log(avr, AV_LOG_ERROR, "Invalid mix coeff type\n");
|
|
||||||
return AVERROR(EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix,
|
|
||||||
int stride)
|
|
||||||
{
|
|
||||||
int in_channels, out_channels, i, o;
|
|
||||||
|
|
||||||
in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout);
|
|
||||||
out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout);
|
|
||||||
|
|
||||||
if ( in_channels <= 0 || in_channels > AVRESAMPLE_MAX_CHANNELS ||
|
|
||||||
out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) {
|
|
||||||
av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n");
|
|
||||||
return AVERROR(EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (avr->am->matrix) {
|
|
||||||
av_free(avr->am->matrix[0]);
|
|
||||||
avr->am->matrix = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define CONVERT_MATRIX(type, expr) \
|
|
||||||
avr->am->matrix_## type[0] = av_mallocz(out_channels * in_channels * \
|
|
||||||
sizeof(*avr->am->matrix_## type[0])); \
|
|
||||||
if (!avr->am->matrix_## type[0]) \
|
|
||||||
return AVERROR(ENOMEM); \
|
|
||||||
for (o = 0; o < out_channels; o++) { \
|
|
||||||
if (o > 0) \
|
|
||||||
avr->am->matrix_## type[o] = avr->am->matrix_## type[o - 1] + \
|
|
||||||
in_channels; \
|
|
||||||
for (i = 0; i < in_channels; i++) { \
|
|
||||||
double v = matrix[o * stride + i]; \
|
|
||||||
avr->am->matrix_## type[o][i] = expr; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
avr->am->matrix = (void **)avr->am->matrix_## type;
|
|
||||||
|
|
||||||
switch (avr->mix_coeff_type) {
|
|
||||||
case AV_MIX_COEFF_TYPE_Q8:
|
|
||||||
CONVERT_MATRIX(q8, av_clip_int16(lrint(256.0 * v)))
|
|
||||||
break;
|
|
||||||
case AV_MIX_COEFF_TYPE_Q15:
|
|
||||||
CONVERT_MATRIX(q15, av_clipl_int32(llrint(32768.0 * v)))
|
|
||||||
break;
|
|
||||||
case AV_MIX_COEFF_TYPE_FLT:
|
|
||||||
CONVERT_MATRIX(flt, v)
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
av_log(avr, AV_LOG_ERROR, "Invalid mix coeff type\n");
|
|
||||||
return AVERROR(EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO: detect situations where we can just swap around pointers
|
|
||||||
instead of doing matrix multiplications with 0.0 and 1.0 */
|
|
||||||
|
|
||||||
/* set AudioMix params */
|
|
||||||
avr->am->in_layout = avr->in_channel_layout;
|
|
||||||
avr->am->out_layout = avr->out_channel_layout;
|
|
||||||
avr->am->in_channels = in_channels;
|
|
||||||
avr->am->out_channels = out_channels;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
@ -216,6 +216,9 @@ int avresample_build_matrix(uint64_t in_layout, uint64_t out_layout,
|
|||||||
/**
|
/**
|
||||||
* Get the current channel mixing matrix.
|
* Get the current channel mixing matrix.
|
||||||
*
|
*
|
||||||
|
* If no custom matrix has been previously set or the AVAudioResampleContext is
|
||||||
|
* not open, an error is returned.
|
||||||
|
*
|
||||||
* @param avr audio resample context
|
* @param avr audio resample context
|
||||||
* @param matrix mixing coefficients; matrix[i + stride * o] is the weight of
|
* @param matrix mixing coefficients; matrix[i + stride * o] is the weight of
|
||||||
* input channel i in output channel o.
|
* input channel i in output channel o.
|
||||||
@ -231,7 +234,8 @@ int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix,
|
|||||||
* Allows for setting a custom mixing matrix, overriding the default matrix
|
* Allows for setting a custom mixing matrix, overriding the default matrix
|
||||||
* generated internally during avresample_open(). This function can be called
|
* generated internally during avresample_open(). This function can be called
|
||||||
* anytime on an allocated context, either before or after calling
|
* anytime on an allocated context, either before or after calling
|
||||||
* avresample_open(). avresample_convert() always uses the current matrix.
|
* avresample_open(), as long as the channel layouts have been set.
|
||||||
|
* avresample_convert() always uses the current matrix.
|
||||||
* Calling avresample_close() on the context will clear the current matrix.
|
* Calling avresample_close() on the context will clear the current matrix.
|
||||||
*
|
*
|
||||||
* @see avresample_close()
|
* @see avresample_close()
|
||||||
|
@ -74,6 +74,12 @@ struct AVAudioResampleContext {
|
|||||||
ResampleContext *resample; /**< resampling context */
|
ResampleContext *resample; /**< resampling context */
|
||||||
AudioMix *am; /**< channel mixing context */
|
AudioMix *am; /**< channel mixing context */
|
||||||
enum AVMatrixEncoding matrix_encoding; /**< matrixed stereo encoding */
|
enum AVMatrixEncoding matrix_encoding; /**< matrixed stereo encoding */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mix matrix
|
||||||
|
* only used if avresample_set_matrix() is called before avresample_open()
|
||||||
|
*/
|
||||||
|
double *mix_matrix;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* AVRESAMPLE_INTERNAL_H */
|
#endif /* AVRESAMPLE_INTERNAL_H */
|
||||||
|
@ -84,13 +84,6 @@ AVAudioResampleContext *avresample_alloc_context(void)
|
|||||||
avr->av_class = &av_resample_context_class;
|
avr->av_class = &av_resample_context_class;
|
||||||
av_opt_set_defaults(avr);
|
av_opt_set_defaults(avr);
|
||||||
|
|
||||||
avr->am = av_mallocz(sizeof(*avr->am));
|
|
||||||
if (!avr->am) {
|
|
||||||
av_free(avr);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
avr->am->avr = avr;
|
|
||||||
|
|
||||||
return avr;
|
return avr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,9 +169,11 @@ int avresample_open(AVAudioResampleContext *avr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (avr->mixing_needed) {
|
if (avr->mixing_needed) {
|
||||||
ret = ff_audio_mix_init(avr);
|
avr->am = ff_audio_mix_alloc(avr);
|
||||||
if (ret < 0)
|
if (!avr->am) {
|
||||||
|
ret = AVERROR(ENOMEM);
|
||||||
goto error;
|
goto error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -191,8 +193,8 @@ void avresample_close(AVAudioResampleContext *avr)
|
|||||||
av_freep(&avr->ac_in);
|
av_freep(&avr->ac_in);
|
||||||
av_freep(&avr->ac_out);
|
av_freep(&avr->ac_out);
|
||||||
ff_audio_resample_free(&avr->resample);
|
ff_audio_resample_free(&avr->resample);
|
||||||
ff_audio_mix_close(avr->am);
|
ff_audio_mix_free(&avr->am);
|
||||||
return;
|
av_freep(&avr->mix_matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
void avresample_free(AVAudioResampleContext **avr)
|
void avresample_free(AVAudioResampleContext **avr)
|
||||||
@ -200,7 +202,6 @@ void avresample_free(AVAudioResampleContext **avr)
|
|||||||
if (!*avr)
|
if (!*avr)
|
||||||
return;
|
return;
|
||||||
avresample_close(*avr);
|
avresample_close(*avr);
|
||||||
av_freep(&(*avr)->am);
|
|
||||||
av_opt_free(*avr);
|
av_opt_free(*avr);
|
||||||
av_freep(avr);
|
av_freep(avr);
|
||||||
}
|
}
|
||||||
@ -404,6 +405,66 @@ int attribute_align_arg avresample_convert(AVAudioResampleContext *avr,
|
|||||||
current_buffer);
|
current_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix,
|
||||||
|
int stride)
|
||||||
|
{
|
||||||
|
int in_channels, out_channels, i, o;
|
||||||
|
|
||||||
|
if (avr->am)
|
||||||
|
return ff_audio_mix_get_matrix(avr->am, matrix, stride);
|
||||||
|
|
||||||
|
in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout);
|
||||||
|
out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout);
|
||||||
|
|
||||||
|
if ( in_channels <= 0 || in_channels > AVRESAMPLE_MAX_CHANNELS ||
|
||||||
|
out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) {
|
||||||
|
av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n");
|
||||||
|
return AVERROR(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!avr->mix_matrix) {
|
||||||
|
av_log(avr, AV_LOG_ERROR, "matrix is not set\n");
|
||||||
|
return AVERROR(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (o = 0; o < out_channels; o++)
|
||||||
|
for (i = 0; i < in_channels; i++)
|
||||||
|
matrix[o * stride + i] = avr->mix_matrix[o * in_channels + i];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix,
|
||||||
|
int stride)
|
||||||
|
{
|
||||||
|
int in_channels, out_channels, i, o;
|
||||||
|
|
||||||
|
if (avr->am)
|
||||||
|
return ff_audio_mix_set_matrix(avr->am, matrix, stride);
|
||||||
|
|
||||||
|
in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout);
|
||||||
|
out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout);
|
||||||
|
|
||||||
|
if ( in_channels <= 0 || in_channels > AVRESAMPLE_MAX_CHANNELS ||
|
||||||
|
out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) {
|
||||||
|
av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n");
|
||||||
|
return AVERROR(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (avr->mix_matrix)
|
||||||
|
av_freep(&avr->mix_matrix);
|
||||||
|
avr->mix_matrix = av_malloc(in_channels * out_channels *
|
||||||
|
sizeof(*avr->mix_matrix));
|
||||||
|
if (!avr->mix_matrix)
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
|
for (o = 0; o < out_channels; o++)
|
||||||
|
for (i = 0; i < in_channels; i++)
|
||||||
|
avr->mix_matrix[o * in_channels + i] = matrix[o * stride + i];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int avresample_available(AVAudioResampleContext *avr)
|
int avresample_available(AVAudioResampleContext *avr)
|
||||||
{
|
{
|
||||||
return av_audio_fifo_size(avr->out_fifo);
|
return av_audio_fifo_size(avr->out_fifo);
|
||||||
|
Loading…
Reference in New Issue
Block a user