mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-30 13:41:48 +00:00
libs: audio-converter: complete code to support non-interleaved audio buffers
https://bugzilla.gnome.org/show_bug.cgi?id=705986
This commit is contained in:
parent
eefdf32d96
commit
060ecd16cd
1 changed files with 156 additions and 12 deletions
|
@ -131,6 +131,11 @@ struct _GstAudioConverter
|
||||||
/* quant */
|
/* quant */
|
||||||
GstAudioQuantize *quant;
|
GstAudioQuantize *quant;
|
||||||
|
|
||||||
|
/* change layout */
|
||||||
|
GstAudioFormat chlayout_format;
|
||||||
|
GstAudioLayout chlayout_target;
|
||||||
|
gint chlayout_channels;
|
||||||
|
|
||||||
/* pack */
|
/* pack */
|
||||||
gboolean out_default;
|
gboolean out_default;
|
||||||
AudioChain *chain_end; /* NULL for empty chain or points to the last element in the chain */
|
AudioChain *chain_end; /* NULL for empty chain or points to the last element in the chain */
|
||||||
|
@ -582,6 +587,110 @@ do_quantize (AudioChain * chain, gpointer user_data)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MAKE_INTERLEAVE_FUNC(type) \
|
||||||
|
static inline void \
|
||||||
|
interleave_##type (const type * in[], type * out[], \
|
||||||
|
gsize num_samples, gint channels) \
|
||||||
|
{ \
|
||||||
|
gsize s; \
|
||||||
|
gint c; \
|
||||||
|
for (s = 0; s < num_samples; s++) { \
|
||||||
|
for (c = 0; c < channels; c++) { \
|
||||||
|
out[0][s * channels + c] = in[c][s]; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAKE_DEINTERLEAVE_FUNC(type) \
|
||||||
|
static inline void \
|
||||||
|
deinterleave_##type (const type * in[], type * out[], \
|
||||||
|
gsize num_samples, gint channels) \
|
||||||
|
{ \
|
||||||
|
gsize s; \
|
||||||
|
gint c; \
|
||||||
|
for (s = 0; s < num_samples; s++) { \
|
||||||
|
for (c = 0; c < channels; c++) { \
|
||||||
|
out[c][s] = in[0][s * channels + c]; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
MAKE_INTERLEAVE_FUNC (gint16);
|
||||||
|
MAKE_INTERLEAVE_FUNC (gint32);
|
||||||
|
MAKE_INTERLEAVE_FUNC (gfloat);
|
||||||
|
MAKE_INTERLEAVE_FUNC (gdouble);
|
||||||
|
MAKE_DEINTERLEAVE_FUNC (gint16);
|
||||||
|
MAKE_DEINTERLEAVE_FUNC (gint32);
|
||||||
|
MAKE_DEINTERLEAVE_FUNC (gfloat);
|
||||||
|
MAKE_DEINTERLEAVE_FUNC (gdouble);
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
do_change_layout (AudioChain * chain, gpointer user_data)
|
||||||
|
{
|
||||||
|
GstAudioConverter *convert = user_data;
|
||||||
|
GstAudioFormat format = convert->chlayout_format;
|
||||||
|
GstAudioLayout out_layout = convert->chlayout_target;
|
||||||
|
gint channels = convert->chlayout_channels;
|
||||||
|
gsize num_samples;
|
||||||
|
gpointer *in, *out;
|
||||||
|
|
||||||
|
in = audio_chain_get_samples (chain->prev, &num_samples);
|
||||||
|
out = (chain->allow_ip ? in : audio_chain_alloc_samples (chain, num_samples));
|
||||||
|
|
||||||
|
if (out_layout == GST_AUDIO_LAYOUT_INTERLEAVED) {
|
||||||
|
/* interleave */
|
||||||
|
GST_LOG ("interleaving %p, %p %" G_GSIZE_FORMAT, in, out, num_samples);
|
||||||
|
switch (format) {
|
||||||
|
case GST_AUDIO_FORMAT_S16:
|
||||||
|
interleave_gint16 ((const gint16 **) in, (gint16 **) out,
|
||||||
|
num_samples, channels);
|
||||||
|
break;
|
||||||
|
case GST_AUDIO_FORMAT_S32:
|
||||||
|
interleave_gint32 ((const gint32 **) in, (gint32 **) out,
|
||||||
|
num_samples, channels);
|
||||||
|
break;
|
||||||
|
case GST_AUDIO_FORMAT_F32:
|
||||||
|
interleave_gfloat ((const gfloat **) in, (gfloat **) out,
|
||||||
|
num_samples, channels);
|
||||||
|
break;
|
||||||
|
case GST_AUDIO_FORMAT_F64:
|
||||||
|
interleave_gdouble ((const gdouble **) in, (gdouble **) out,
|
||||||
|
num_samples, channels);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* deinterleave */
|
||||||
|
GST_LOG ("deinterleaving %p, %p %" G_GSIZE_FORMAT, in, out, num_samples);
|
||||||
|
switch (format) {
|
||||||
|
case GST_AUDIO_FORMAT_S16:
|
||||||
|
deinterleave_gint16 ((const gint16 **) in, (gint16 **) out,
|
||||||
|
num_samples, channels);
|
||||||
|
break;
|
||||||
|
case GST_AUDIO_FORMAT_S32:
|
||||||
|
deinterleave_gint32 ((const gint32 **) in, (gint32 **) out,
|
||||||
|
num_samples, channels);
|
||||||
|
break;
|
||||||
|
case GST_AUDIO_FORMAT_F32:
|
||||||
|
deinterleave_gfloat ((const gfloat **) in, (gfloat **) out,
|
||||||
|
num_samples, channels);
|
||||||
|
break;
|
||||||
|
case GST_AUDIO_FORMAT_F64:
|
||||||
|
deinterleave_gdouble ((const gdouble **) in, (gdouble **) out,
|
||||||
|
num_samples, channels);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
audio_chain_set_samples (chain, out, num_samples);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
is_intermediate_format (GstAudioFormat format)
|
is_intermediate_format (GstAudioFormat format)
|
||||||
{
|
{
|
||||||
|
@ -719,9 +828,16 @@ chain_mix (GstAudioConverter * convert, AudioChain * prev)
|
||||||
GstAudioInfo *out = &convert->out;
|
GstAudioInfo *out = &convert->out;
|
||||||
GstAudioFormat format = convert->current_format;
|
GstAudioFormat format = convert->current_format;
|
||||||
const GValue *opt_matrix = GET_OPT_MIX_MATRIX (convert);
|
const GValue *opt_matrix = GET_OPT_MIX_MATRIX (convert);
|
||||||
|
GstAudioChannelMixerFlags flags = 0;
|
||||||
|
|
||||||
convert->current_channels = out->channels;
|
convert->current_channels = out->channels;
|
||||||
|
|
||||||
|
/* keep the input layout */
|
||||||
|
if (convert->current_layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
|
||||||
|
flags |= GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_IN;
|
||||||
|
flags |= GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT;
|
||||||
|
}
|
||||||
|
|
||||||
if (opt_matrix) {
|
if (opt_matrix) {
|
||||||
gfloat **matrix = NULL;
|
gfloat **matrix = NULL;
|
||||||
|
|
||||||
|
@ -730,12 +846,10 @@ chain_mix (GstAudioConverter * convert, AudioChain * prev)
|
||||||
mix_matrix_from_g_value (in->channels, out->channels, opt_matrix);
|
mix_matrix_from_g_value (in->channels, out->channels, opt_matrix);
|
||||||
|
|
||||||
convert->mix =
|
convert->mix =
|
||||||
gst_audio_channel_mixer_new_with_matrix (0, format, in->channels,
|
gst_audio_channel_mixer_new_with_matrix (flags, format, in->channels,
|
||||||
out->channels, matrix);
|
out->channels, matrix);
|
||||||
} else {
|
} else {
|
||||||
GstAudioChannelMixerFlags flags;
|
flags |=
|
||||||
|
|
||||||
flags =
|
|
||||||
GST_AUDIO_INFO_IS_UNPOSITIONED (in) ?
|
GST_AUDIO_INFO_IS_UNPOSITIONED (in) ?
|
||||||
GST_AUDIO_CHANNEL_MIXER_FLAGS_UNPOSITIONED_IN : 0;
|
GST_AUDIO_CHANNEL_MIXER_FLAGS_UNPOSITIONED_IN : 0;
|
||||||
flags |=
|
flags |=
|
||||||
|
@ -781,8 +895,13 @@ chain_resample (GstAudioConverter * convert, AudioChain * prev)
|
||||||
flags = 0;
|
flags = 0;
|
||||||
if (convert->current_layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
|
if (convert->current_layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
|
||||||
flags |= GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED_IN;
|
flags |= GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED_IN;
|
||||||
|
}
|
||||||
|
/* if the resampler is activated, it is optimal to change layout here */
|
||||||
|
if (out->layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
|
||||||
flags |= GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED_OUT;
|
flags |= GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED_OUT;
|
||||||
}
|
}
|
||||||
|
convert->current_layout = out->layout;
|
||||||
|
|
||||||
if (variable_rate)
|
if (variable_rate)
|
||||||
flags |= GST_AUDIO_RESAMPLER_FLAG_VARIABLE_RATE;
|
flags |= GST_AUDIO_RESAMPLER_FLAG_VARIABLE_RATE;
|
||||||
|
|
||||||
|
@ -875,6 +994,29 @@ chain_quantize (GstAudioConverter * convert, AudioChain * prev)
|
||||||
return prev;
|
return prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static AudioChain *
|
||||||
|
chain_change_layout (GstAudioConverter * convert, AudioChain * prev)
|
||||||
|
{
|
||||||
|
GstAudioInfo *out = &convert->out;
|
||||||
|
|
||||||
|
if (convert->current_layout != out->layout) {
|
||||||
|
convert->current_layout = out->layout;
|
||||||
|
|
||||||
|
/* if there is only 1 channel, layouts are identical */
|
||||||
|
if (convert->current_channels > 1) {
|
||||||
|
convert->chlayout_target = convert->current_layout;
|
||||||
|
convert->chlayout_format = convert->current_format;
|
||||||
|
convert->chlayout_channels = convert->current_channels;
|
||||||
|
|
||||||
|
prev = audio_chain_new (prev, convert);
|
||||||
|
prev->allow_ip = FALSE;
|
||||||
|
prev->pass_alloc = FALSE;
|
||||||
|
audio_chain_set_make_func (prev, do_change_layout, convert, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
static AudioChain *
|
static AudioChain *
|
||||||
chain_pack (GstAudioConverter * convert, AudioChain * prev)
|
chain_pack (GstAudioConverter * convert, AudioChain * prev)
|
||||||
{
|
{
|
||||||
|
@ -1184,8 +1326,6 @@ gst_audio_converter_new (GstAudioConverterFlags flags, GstAudioInfo * in_info,
|
||||||
|
|
||||||
g_return_val_if_fail (in_info != NULL, FALSE);
|
g_return_val_if_fail (in_info != NULL, FALSE);
|
||||||
g_return_val_if_fail (out_info != NULL, FALSE);
|
g_return_val_if_fail (out_info != NULL, FALSE);
|
||||||
g_return_val_if_fail (in_info->layout == GST_AUDIO_LAYOUT_INTERLEAVED, FALSE);
|
|
||||||
g_return_val_if_fail (in_info->layout == out_info->layout, FALSE);
|
|
||||||
|
|
||||||
if (config)
|
if (config)
|
||||||
opt_matrix =
|
opt_matrix =
|
||||||
|
@ -1226,7 +1366,9 @@ gst_audio_converter_new (GstAudioConverterFlags flags, GstAudioInfo * in_info,
|
||||||
prev = chain_convert_out (convert, prev);
|
prev = chain_convert_out (convert, prev);
|
||||||
/* step 6, optional quantize */
|
/* step 6, optional quantize */
|
||||||
prev = chain_quantize (convert, prev);
|
prev = chain_quantize (convert, prev);
|
||||||
/* step 7, pack */
|
/* step 7, change layout */
|
||||||
|
prev = chain_change_layout (convert, prev);
|
||||||
|
/* step 8, pack */
|
||||||
convert->chain_end = chain_pack (convert, prev);
|
convert->chain_end = chain_pack (convert, prev);
|
||||||
|
|
||||||
convert->convert = converter_generic;
|
convert->convert = converter_generic;
|
||||||
|
@ -1236,10 +1378,12 @@ gst_audio_converter_new (GstAudioConverterFlags flags, GstAudioInfo * in_info,
|
||||||
if (convert->mix_passthrough) {
|
if (convert->mix_passthrough) {
|
||||||
if (out_info->finfo->format == in_info->finfo->format) {
|
if (out_info->finfo->format == in_info->finfo->format) {
|
||||||
if (convert->resampler == NULL) {
|
if (convert->resampler == NULL) {
|
||||||
GST_INFO
|
if (out_info->layout == in_info->layout) {
|
||||||
("same formats, no resampler and passthrough mixing -> passthrough");
|
GST_INFO ("same formats, same layout, no resampler and "
|
||||||
convert->convert = converter_passthrough;
|
"passthrough mixing -> passthrough");
|
||||||
convert->in_place = TRUE;
|
convert->convert = converter_passthrough;
|
||||||
|
convert->in_place = TRUE;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (is_intermediate_format (in_info->finfo->format)) {
|
if (is_intermediate_format (in_info->finfo->format)) {
|
||||||
GST_INFO ("same formats, and passthrough mixing -> only resampling");
|
GST_INFO ("same formats, and passthrough mixing -> only resampling");
|
||||||
|
@ -1248,7 +1392,7 @@ gst_audio_converter_new (GstAudioConverterFlags flags, GstAudioInfo * in_info,
|
||||||
}
|
}
|
||||||
} else if (GST_AUDIO_FORMAT_IS_ENDIAN_CONVERSION (out_info->finfo,
|
} else if (GST_AUDIO_FORMAT_IS_ENDIAN_CONVERSION (out_info->finfo,
|
||||||
in_info->finfo)) {
|
in_info->finfo)) {
|
||||||
if (convert->resampler == NULL) {
|
if (convert->resampler == NULL && out_info->layout == in_info->layout) {
|
||||||
GST_INFO ("no resampler, passthrough mixing -> only endian conversion");
|
GST_INFO ("no resampler, passthrough mixing -> only endian conversion");
|
||||||
convert->convert = converter_endian;
|
convert->convert = converter_endian;
|
||||||
convert->in_place = TRUE;
|
convert->in_place = TRUE;
|
||||||
|
|
Loading…
Reference in a new issue