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;
|
||||
}
|
||||
|
||||
int ff_audio_mix_init(AVAudioResampleContext *avr)
|
||||
AudioMix *ff_audio_mix_alloc(AVAudioResampleContext *avr)
|
||||
{
|
||||
AudioMix *am;
|
||||
int ret;
|
||||
|
||||
am = av_mallocz(sizeof(*am));
|
||||
if (!am)
|
||||
return NULL;
|
||||
am->avr = avr;
|
||||
|
||||
if (avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P &&
|
||||
avr->internal_sample_fmt != AV_SAMPLE_FMT_FLTP) {
|
||||
av_log(avr, AV_LOG_ERROR, "Unsupported internal format for "
|
||||
"mixing: %s\n",
|
||||
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 */
|
||||
if (avr->am->matrix) {
|
||||
if (avr->am->coeff_type != avr->mix_coeff_type ||
|
||||
avr->am->in_layout != avr->in_channel_layout ||
|
||||
avr->am->out_layout != avr->out_channel_layout) {
|
||||
av_log(avr, AV_LOG_ERROR,
|
||||
"Custom matrix does not match current parameters\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
if (avr->mix_matrix) {
|
||||
ret = ff_audio_mix_set_matrix(am, avr->mix_matrix, avr->in_channels);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
av_freep(&avr->mix_matrix);
|
||||
} else {
|
||||
int i, j;
|
||||
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 *
|
||||
sizeof(*matrix_dbl));
|
||||
if (!matrix_dbl)
|
||||
return AVERROR(ENOMEM);
|
||||
goto error;
|
||||
|
||||
ret = avresample_build_matrix(avr->in_channel_layout,
|
||||
avr->out_channel_layout,
|
||||
@ -343,7 +353,7 @@ int ff_audio_mix_init(AVAudioResampleContext *avr)
|
||||
avr->matrix_encoding);
|
||||
if (ret < 0) {
|
||||
av_free(matrix_dbl);
|
||||
return ret;
|
||||
goto error;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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) {
|
||||
av_free(matrix_dbl);
|
||||
return ret;
|
||||
goto error;
|
||||
}
|
||||
av_free(matrix_dbl);
|
||||
}
|
||||
|
||||
avr->am->fmt = avr->internal_sample_fmt;
|
||||
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);
|
||||
ret = mix_function_init(am);
|
||||
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;
|
||||
am = *am_p;
|
||||
|
||||
if (am->matrix) {
|
||||
av_free(am->matrix[0]);
|
||||
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_q15, 0, sizeof(am->matrix_q15));
|
||||
memset(am->matrix_flt, 0, sizeof(am->matrix_flt));
|
||||
|
||||
av_freep(am_p);
|
||||
}
|
||||
|
||||
int ff_audio_mix(AudioMix *am, AudioData *src)
|
||||
@ -424,3 +437,92 @@ int ff_audio_mix(AudioMix *am, AudioData *src)
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* Initialize the AudioMix context in the AVAudioResampleContext.
|
||||
* Allocate and initialize an AudioMix context.
|
||||
*
|
||||
* The parameters in the AVAudioResampleContext are used to initialize the
|
||||
* AudioMix context and set the mixing matrix.
|
||||
* AudioMix context.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* This clears and frees the mixing matrix arrays.
|
||||
* Free an AudioMix context.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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 */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
* If no custom matrix has been previously set or the AVAudioResampleContext is
|
||||
* not open, an error is returned.
|
||||
*
|
||||
* @param avr audio resample context
|
||||
* @param matrix mixing coefficients; matrix[i + stride * o] is the weight of
|
||||
* 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
|
||||
* generated internally during avresample_open(). This function can be called
|
||||
* 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.
|
||||
*
|
||||
* @see avresample_close()
|
||||
|
@ -74,6 +74,12 @@ struct AVAudioResampleContext {
|
||||
ResampleContext *resample; /**< resampling context */
|
||||
AudioMix *am; /**< channel mixing context */
|
||||
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 */
|
||||
|
@ -84,13 +84,6 @@ AVAudioResampleContext *avresample_alloc_context(void)
|
||||
avr->av_class = &av_resample_context_class;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -169,9 +169,11 @@ int avresample_open(AVAudioResampleContext *avr)
|
||||
}
|
||||
}
|
||||
if (avr->mixing_needed) {
|
||||
ret = ff_audio_mix_init(avr);
|
||||
if (ret < 0)
|
||||
avr->am = ff_audio_mix_alloc(avr);
|
||||
if (!avr->am) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -191,8 +193,8 @@ void avresample_close(AVAudioResampleContext *avr)
|
||||
av_freep(&avr->ac_in);
|
||||
av_freep(&avr->ac_out);
|
||||
ff_audio_resample_free(&avr->resample);
|
||||
ff_audio_mix_close(avr->am);
|
||||
return;
|
||||
ff_audio_mix_free(&avr->am);
|
||||
av_freep(&avr->mix_matrix);
|
||||
}
|
||||
|
||||
void avresample_free(AVAudioResampleContext **avr)
|
||||
@ -200,7 +202,6 @@ void avresample_free(AVAudioResampleContext **avr)
|
||||
if (!*avr)
|
||||
return;
|
||||
avresample_close(*avr);
|
||||
av_freep(&(*avr)->am);
|
||||
av_opt_free(*avr);
|
||||
av_freep(avr);
|
||||
}
|
||||
@ -404,6 +405,66 @@ int attribute_align_arg avresample_convert(AVAudioResampleContext *avr,
|
||||
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)
|
||||
{
|
||||
return av_audio_fifo_size(avr->out_fifo);
|
||||
|
Loading…
Reference in New Issue
Block a user