mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-26 18:20:44 +00:00
libs: audio-channel-mixer: add support for non-interleaved audio buffers
https://bugzilla.gnome.org/show_bug.cgi?id=705986
This commit is contained in:
parent
294bfb7300
commit
108a911610
1 changed files with 173 additions and 93 deletions
|
@ -54,8 +54,8 @@ ensure_debug_category (void)
|
||||||
|
|
||||||
#define PRECISION_INT 10
|
#define PRECISION_INT 10
|
||||||
|
|
||||||
typedef void (*MixerFunc) (GstAudioChannelMixer * mix, const gpointer src,
|
typedef void (*MixerFunc) (GstAudioChannelMixer * mix, const gpointer src[],
|
||||||
gpointer dst, gint samples);
|
gpointer dst[], gint samples);
|
||||||
|
|
||||||
struct _GstAudioChannelMixer
|
struct _GstAudioChannelMixer
|
||||||
{
|
{
|
||||||
|
@ -694,101 +694,117 @@ gst_audio_channel_mixer_setup_matrix (GstAudioChannelMixerFlags flags,
|
||||||
return matrix;
|
return matrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
#define DEFINE_GET_DATA_FUNCS(type) \
|
||||||
gst_audio_channel_mixer_mix_int16 (GstAudioChannelMixer * mix,
|
static inline type \
|
||||||
const gint16 * in_data, gint16 * out_data, gint samples)
|
_get_in_data_interleaved_##type (const type * in_data[], \
|
||||||
{
|
gint sample, gint channel, gint total_channels) \
|
||||||
gint in, out, n;
|
{ \
|
||||||
gint32 res;
|
return in_data[0][sample * total_channels + channel]; \
|
||||||
gint inchannels, outchannels;
|
} \
|
||||||
|
\
|
||||||
inchannels = mix->in_channels;
|
static inline type * \
|
||||||
outchannels = mix->out_channels;
|
_get_out_data_interleaved_##type (type * out_data[], \
|
||||||
|
gint sample, gint channel, gint total_channels) \
|
||||||
for (n = 0; n < samples; n++) {
|
{ \
|
||||||
for (out = 0; out < outchannels; out++) {
|
return &out_data[0][sample * total_channels + channel]; \
|
||||||
/* convert */
|
} \
|
||||||
res = 0;
|
\
|
||||||
for (in = 0; in < inchannels; in++)
|
static inline type \
|
||||||
res += in_data[n * inchannels + in] * mix->matrix_int[in][out];
|
_get_in_data_planar_##type (const type * in_data[], \
|
||||||
|
gint sample, gint channel, gint total_channels) \
|
||||||
/* remove factor from int matrix */
|
{ \
|
||||||
res = (res + (1 << (PRECISION_INT - 1))) >> PRECISION_INT;
|
(void) total_channels; \
|
||||||
out_data[n * outchannels + out] = CLAMP (res, G_MININT16, G_MAXINT16);
|
return in_data[channel][sample]; \
|
||||||
}
|
} \
|
||||||
}
|
\
|
||||||
|
static inline type * \
|
||||||
|
_get_out_data_planar_##type (type * out_data[], \
|
||||||
|
gint sample, gint channel, gint total_channels) \
|
||||||
|
{ \
|
||||||
|
(void) total_channels; \
|
||||||
|
return &out_data[channel][sample]; \
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
#define DEFINE_INTEGER_MIX_FUNC(bits, resbits, inlayout, outlayout) \
|
||||||
gst_audio_channel_mixer_mix_int32 (GstAudioChannelMixer * mix,
|
static void \
|
||||||
const gint32 * in_data, gint32 * out_data, gint samples)
|
gst_audio_channel_mixer_mix_int##bits##_##inlayout##_##outlayout ( \
|
||||||
{
|
GstAudioChannelMixer * mix, const gint##bits * in_data[], \
|
||||||
gint in, out, n;
|
gint##bits * out_data[], gint samples) \
|
||||||
gint64 res;
|
{ \
|
||||||
gint inchannels, outchannels;
|
gint in, out, n; \
|
||||||
|
gint##resbits res; \
|
||||||
inchannels = mix->in_channels;
|
gint inchannels, outchannels; \
|
||||||
outchannels = mix->out_channels;
|
\
|
||||||
|
inchannels = mix->in_channels; \
|
||||||
for (n = 0; n < samples; n++) {
|
outchannels = mix->out_channels; \
|
||||||
for (out = 0; out < outchannels; out++) {
|
\
|
||||||
/* convert */
|
for (n = 0; n < samples; n++) { \
|
||||||
res = 0;
|
for (out = 0; out < outchannels; out++) { \
|
||||||
for (in = 0; in < inchannels; in++)
|
/* convert */ \
|
||||||
res += in_data[n * inchannels + in] * (gint64) mix->matrix_int[in][out];
|
res = 0; \
|
||||||
|
for (in = 0; in < inchannels; in++) \
|
||||||
/* remove factor from int matrix */
|
res += \
|
||||||
res = (res + (1 << (PRECISION_INT - 1))) >> PRECISION_INT;
|
_get_in_data_##inlayout##_gint##bits (in_data, n, in, inchannels) * \
|
||||||
out_data[n * outchannels + out] = CLAMP (res, G_MININT32, G_MAXINT32);
|
(gint##resbits) mix->matrix_int[in][out]; \
|
||||||
}
|
\
|
||||||
}
|
/* remove factor from int matrix */ \
|
||||||
|
res = (res + (1 << (PRECISION_INT - 1))) >> PRECISION_INT; \
|
||||||
|
*_get_out_data_##outlayout##_gint##bits (out_data, n, out, outchannels) = \
|
||||||
|
CLAMP (res, G_MININT##bits, G_MAXINT##bits); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
#define DEFINE_FLOAT_MIX_FUNC(type, inlayout, outlayout) \
|
||||||
gst_audio_channel_mixer_mix_float (GstAudioChannelMixer * mix,
|
static void \
|
||||||
const gfloat * in_data, gfloat * out_data, gint samples)
|
gst_audio_channel_mixer_mix_##type##_##inlayout##_##outlayout ( \
|
||||||
{
|
GstAudioChannelMixer * mix, const g##type * in_data[], \
|
||||||
gint in, out, n;
|
g##type * out_data[], gint samples) \
|
||||||
gfloat res;
|
{ \
|
||||||
gint inchannels, outchannels;
|
gint in, out, n; \
|
||||||
|
g##type res; \
|
||||||
inchannels = mix->in_channels;
|
gint inchannels, outchannels; \
|
||||||
outchannels = mix->out_channels;
|
\
|
||||||
|
inchannels = mix->in_channels; \
|
||||||
for (n = 0; n < samples; n++) {
|
outchannels = mix->out_channels; \
|
||||||
for (out = 0; out < outchannels; out++) {
|
\
|
||||||
/* convert */
|
for (n = 0; n < samples; n++) { \
|
||||||
res = 0.0;
|
for (out = 0; out < outchannels; out++) { \
|
||||||
for (in = 0; in < inchannels; in++)
|
/* convert */ \
|
||||||
res += in_data[n * inchannels + in] * mix->matrix[in][out];
|
res = 0.0; \
|
||||||
|
for (in = 0; in < inchannels; in++) \
|
||||||
out_data[n * outchannels + out] = res;
|
res += \
|
||||||
}
|
_get_in_data_##inlayout##_g##type (in_data, n, in, inchannels) * \
|
||||||
}
|
mix->matrix[in][out]; \
|
||||||
|
\
|
||||||
|
*_get_out_data_##outlayout##_g##type (out_data, n, out, outchannels) = res; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
DEFINE_GET_DATA_FUNCS (gint16);
|
||||||
gst_audio_channel_mixer_mix_double (GstAudioChannelMixer * mix,
|
DEFINE_INTEGER_MIX_FUNC (16, 32, interleaved, interleaved);
|
||||||
const gdouble * in_data, gdouble * out_data, gint samples)
|
DEFINE_INTEGER_MIX_FUNC (16, 32, interleaved, planar);
|
||||||
{
|
DEFINE_INTEGER_MIX_FUNC (16, 32, planar, interleaved);
|
||||||
gint in, out, n;
|
DEFINE_INTEGER_MIX_FUNC (16, 32, planar, planar);
|
||||||
gdouble res;
|
|
||||||
gint inchannels, outchannels;
|
|
||||||
|
|
||||||
inchannels = mix->in_channels;
|
DEFINE_GET_DATA_FUNCS (gint32);
|
||||||
outchannels = mix->out_channels;
|
DEFINE_INTEGER_MIX_FUNC (32, 64, interleaved, interleaved);
|
||||||
|
DEFINE_INTEGER_MIX_FUNC (32, 64, interleaved, planar);
|
||||||
|
DEFINE_INTEGER_MIX_FUNC (32, 64, planar, interleaved);
|
||||||
|
DEFINE_INTEGER_MIX_FUNC (32, 64, planar, planar);
|
||||||
|
|
||||||
for (n = 0; n < samples; n++) {
|
DEFINE_GET_DATA_FUNCS (gfloat);
|
||||||
for (out = 0; out < outchannels; out++) {
|
DEFINE_FLOAT_MIX_FUNC (float, interleaved, interleaved);
|
||||||
/* convert */
|
DEFINE_FLOAT_MIX_FUNC (float, interleaved, planar);
|
||||||
res = 0.0;
|
DEFINE_FLOAT_MIX_FUNC (float, planar, interleaved);
|
||||||
for (in = 0; in < inchannels; in++)
|
DEFINE_FLOAT_MIX_FUNC (float, planar, planar);
|
||||||
res += in_data[n * inchannels + in] * mix->matrix[in][out];
|
|
||||||
|
|
||||||
out_data[n * outchannels + out] = res;
|
DEFINE_GET_DATA_FUNCS (gdouble);
|
||||||
}
|
DEFINE_FLOAT_MIX_FUNC (double, interleaved, interleaved);
|
||||||
}
|
DEFINE_FLOAT_MIX_FUNC (double, interleaved, planar);
|
||||||
}
|
DEFINE_FLOAT_MIX_FUNC (double, planar, interleaved);
|
||||||
|
DEFINE_FLOAT_MIX_FUNC (double, planar, planar);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_audio_channel_mixer_new_with_matrix: (skip):
|
* gst_audio_channel_mixer_new_with_matrix: (skip):
|
||||||
|
@ -872,16 +888,80 @@ gst_audio_channel_mixer_new_with_matrix (GstAudioChannelMixerFlags flags,
|
||||||
|
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case GST_AUDIO_FORMAT_S16:
|
case GST_AUDIO_FORMAT_S16:
|
||||||
mix->func = (MixerFunc) gst_audio_channel_mixer_mix_int16;
|
if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_IN) {
|
||||||
|
if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT) {
|
||||||
|
mix->func = (MixerFunc)
|
||||||
|
gst_audio_channel_mixer_mix_int16_planar_planar;
|
||||||
|
} else {
|
||||||
|
mix->func = (MixerFunc)
|
||||||
|
gst_audio_channel_mixer_mix_int16_planar_interleaved;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT) {
|
||||||
|
mix->func = (MixerFunc)
|
||||||
|
gst_audio_channel_mixer_mix_int16_interleaved_planar;
|
||||||
|
} else {
|
||||||
|
mix->func = (MixerFunc)
|
||||||
|
gst_audio_channel_mixer_mix_int16_interleaved_interleaved;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case GST_AUDIO_FORMAT_S32:
|
case GST_AUDIO_FORMAT_S32:
|
||||||
mix->func = (MixerFunc) gst_audio_channel_mixer_mix_int32;
|
if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_IN) {
|
||||||
|
if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT) {
|
||||||
|
mix->func = (MixerFunc)
|
||||||
|
gst_audio_channel_mixer_mix_int32_planar_planar;
|
||||||
|
} else {
|
||||||
|
mix->func = (MixerFunc)
|
||||||
|
gst_audio_channel_mixer_mix_int32_planar_interleaved;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT) {
|
||||||
|
mix->func = (MixerFunc)
|
||||||
|
gst_audio_channel_mixer_mix_int32_interleaved_planar;
|
||||||
|
} else {
|
||||||
|
mix->func = (MixerFunc)
|
||||||
|
gst_audio_channel_mixer_mix_int32_interleaved_interleaved;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case GST_AUDIO_FORMAT_F32:
|
case GST_AUDIO_FORMAT_F32:
|
||||||
mix->func = (MixerFunc) gst_audio_channel_mixer_mix_float;
|
if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_IN) {
|
||||||
|
if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT) {
|
||||||
|
mix->func = (MixerFunc)
|
||||||
|
gst_audio_channel_mixer_mix_float_planar_planar;
|
||||||
|
} else {
|
||||||
|
mix->func = (MixerFunc)
|
||||||
|
gst_audio_channel_mixer_mix_float_planar_interleaved;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT) {
|
||||||
|
mix->func = (MixerFunc)
|
||||||
|
gst_audio_channel_mixer_mix_float_interleaved_planar;
|
||||||
|
} else {
|
||||||
|
mix->func = (MixerFunc)
|
||||||
|
gst_audio_channel_mixer_mix_float_interleaved_interleaved;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case GST_AUDIO_FORMAT_F64:
|
case GST_AUDIO_FORMAT_F64:
|
||||||
mix->func = (MixerFunc) gst_audio_channel_mixer_mix_double;
|
if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_IN) {
|
||||||
|
if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT) {
|
||||||
|
mix->func = (MixerFunc)
|
||||||
|
gst_audio_channel_mixer_mix_double_planar_planar;
|
||||||
|
} else {
|
||||||
|
mix->func = (MixerFunc)
|
||||||
|
gst_audio_channel_mixer_mix_double_planar_interleaved;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT) {
|
||||||
|
mix->func = (MixerFunc)
|
||||||
|
gst_audio_channel_mixer_mix_double_interleaved_planar;
|
||||||
|
} else {
|
||||||
|
mix->func = (MixerFunc)
|
||||||
|
gst_audio_channel_mixer_mix_double_interleaved_interleaved;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
|
@ -992,5 +1072,5 @@ gst_audio_channel_mixer_samples (GstAudioChannelMixer * mix,
|
||||||
g_return_if_fail (mix != NULL);
|
g_return_if_fail (mix != NULL);
|
||||||
g_return_if_fail (mix->matrix != NULL);
|
g_return_if_fail (mix->matrix != NULL);
|
||||||
|
|
||||||
mix->func (mix, in[0], out[0], samples);
|
mix->func (mix, in, out, samples);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue