audio: adapt API for non-interleaved formats

Allow an array of sample blocks to be passed to the channel mix and
quantizer functions to support non-interleaved formats.
This commit is contained in:
Wim Taymans 2015-12-10 17:46:26 +01:00
parent aec17c63fd
commit f5a3f70571
6 changed files with 69 additions and 46 deletions

View file

@ -882,19 +882,25 @@ gst_audio_channel_mix_is_passthrough (GstAudioChannelMix * mix)
* @mix: a #GstAudioChannelMix
* @format: a #GstAudioFormat
* @layout: a #GstAudioLayout
* @in_data: input samples
* @out_data: output samples
* @in: input samples
* @out: output samples
* @samples: number of samples
*
* In case the samples are interleaved, @in and @out must point to an
* array with a single element pointing to a block of interleaved samples.
*
* If non-interleaved samples are used, @in and @out must point to an
* array with pointers to memory blocks, one for each channel.
*
* Perform channel mixing on @in_data and write the result to @out_data.
* @in_data and @out_data need to be in @format and @layout.
*/
void
gst_audio_channel_mix_samples (GstAudioChannelMix * mix,
const gpointer in_data, gpointer out_data, gint samples)
const gpointer in[], gpointer out[], gint samples)
{
g_return_if_fail (mix != NULL);
g_return_if_fail (mix->matrix != NULL);
mix->func (mix, in_data, out_data, samples);
mix->func (mix, in[0], out[0], samples);
}

View file

@ -61,8 +61,8 @@ gboolean gst_audio_channel_mix_is_passthrough (GstAudioChannelMix *mix);
* Do actual mixing.
*/
void gst_audio_channel_mix_samples (GstAudioChannelMix * mix,
const gpointer in_data,
gpointer out_data,
const gpointer in[],
gpointer out[],
gint samples);
#endif /* __GST_AUDIO_CHANNEL_MIX_H__ */

View file

@ -476,7 +476,7 @@ gst_audio_converter_samples (GstAudioConverter * convert,
else
outbuf = tmpbuf;
gst_audio_channel_mix_samples (convert->mix, inp, outbuf, in_samples);
gst_audio_channel_mix_samples (convert->mix, &inp, &outbuf, in_samples);
inp = outbuf;
}
/* step 4, optional convert F64 -> S32 for quantize */
@ -497,7 +497,7 @@ gst_audio_converter_samples (GstAudioConverter * convert,
else
outbuf = tmpbuf;
gst_audio_quantize_samples (convert->quant, outbuf, inp, in_samples);
gst_audio_quantize_samples (convert->quant, &inp, &outbuf, in_samples);
inp = outbuf;
}

View file

@ -42,15 +42,16 @@ struct _GstAudioQuantize
GstAudioNoiseShapingMethod ns;
GstAudioQuantizeFlags flags;
GstAudioFormat format;
guint channels;
guint quantizer;
guint stride;
guint blocks;
guint shift;
guint32 mask, bias;
/* last random number generated per channel for hifreq TPDF dither */
gpointer last_random;
/* contains the past quantization errors, error[out_channels][count] */
/* contains the past quantization errors, error[channels][count] */
guint error_size;
gpointer error_buf;
/* buffer with dither values */
@ -76,7 +77,7 @@ gst_audio_quantize_quantize_memcpy (GstAudioQuantize * quant,
const gpointer src, gpointer dst, gint samples)
{
if (src != dst)
memcpy (dst, src, samples * sizeof (gint32) * quant->channels);
memcpy (dst, src, samples * sizeof (gint32) * quant->stride);
}
/* Quantize functions for gint32 as intermediate format */
@ -85,7 +86,7 @@ gst_audio_quantize_quantize_int_none_none (GstAudioQuantize * quant,
const gpointer src, gpointer dst, gint samples)
{
audio_orc_int_bias (dst, src, quant->bias, ~quant->mask,
samples * quant->channels);
samples * quant->stride);
}
/* This is the base function, implementing a linear congruential generator
@ -114,8 +115,8 @@ static void
setup_dither_buf (GstAudioQuantize * quant, gint samples)
{
gboolean need_init = FALSE;
gint channels = quant->channels;
gint i, len = samples * channels;
gint stride = quant->stride;
gint i, len = samples * stride;
guint shift = quant->shift;
guint32 bias;
gint32 dither, *d;
@ -156,8 +157,8 @@ setup_dither_buf (GstAudioQuantize * quant, gint samples)
dither = 1 << (shift - 1);
for (i = 0; i < len; i++) {
tmp = RANDOM_INT_DITHER (dither);
d[i] = bias + tmp - last_random[i % channels];
last_random[i % channels] = tmp;
d[i] = bias + tmp - last_random[i % stride];
last_random[i % stride] = tmp;
}
break;
}
@ -171,20 +172,20 @@ gst_audio_quantize_quantize_int_dither_none (GstAudioQuantize * quant,
setup_dither_buf (quant, samples);
audio_orc_int_dither (dst, src, quant->dither_buf, ~quant->mask,
samples * quant->channels);
samples * quant->stride);
}
static void
setup_error_buf (GstAudioQuantize * quant, gint samples)
{
gint channels = quant->channels;
gint len = (samples + quant->n_coeffs) * channels;
gint stride = quant->stride;
gint len = (samples + quant->n_coeffs) * stride;
if (quant->error_size < len) {
quant->error_buf = g_realloc (quant->error_buf, len * sizeof (gint32));
if (quant->error_size == 0)
memset ((gint32 *) quant->error_buf, 0,
channels * quant->n_coeffs * sizeof (gint32));
stride * quant->n_coeffs * sizeof (gint32));
quant->error_size = len;
}
}
@ -194,15 +195,15 @@ gst_audio_quantize_quantize_int_dither_feedback (GstAudioQuantize * quant,
const gpointer src, gpointer dst, gint samples)
{
guint32 mask;
gint i, len, channels;
gint i, len, stride;
const gint32 *s = src;
gint32 *dith, *d = dst, v, o, *e, err;
setup_dither_buf (quant, samples);
setup_error_buf (quant, samples);
channels = quant->channels;
len = samples * channels;
stride = quant->stride;
len = samples * stride;
dith = quant->dither_buf;
e = quant->error_buf;
mask = ~quant->mask;
@ -216,11 +217,11 @@ gst_audio_quantize_quantize_int_dither_feedback (GstAudioQuantize * quant,
ADDSS (v, err);
v &= mask;
/* store new error */
e[i + channels] = e[i] + (v - o);
e[i + stride] = e[i] + (v - o);
/* store result */
d[i] = v;
}
memmove (e, &e[len], sizeof (gint32) * channels);
memmove (e, &e[len], sizeof (gint32) * stride);
}
#define SHIFT 10
@ -234,15 +235,15 @@ gst_audio_quantize_quantize_int_dither_noise_shape (GstAudioQuantize * quant,
const gpointer src, gpointer dst, gint samples)
{
guint32 mask;
gint i, j, k, len, channels, nc;
gint i, j, k, len, stride, nc;
const gint32 *s = src;
gint32 *c, *dith, *d = dst, v, o, *e, err;
setup_dither_buf (quant, samples);
setup_error_buf (quant, samples);
channels = quant->channels;
len = samples * channels;
stride = quant->stride;
len = samples * stride;
dith = quant->dither_buf;
e = quant->error_buf;
c = quant->coeffs;
@ -253,7 +254,7 @@ gst_audio_quantize_quantize_int_dither_noise_shape (GstAudioQuantize * quant,
v = s[i];
/* combine and remove error */
err = 0;
for (j = 0, k = i; j < nc; j++, k += channels)
for (j = 0, k = i; j < nc; j++, k += stride)
err -= e[k] * c[j];
err = (err + SROUND) >> (SREDUCE);
ADDSS (v, err);
@ -268,7 +269,7 @@ gst_audio_quantize_quantize_int_dither_noise_shape (GstAudioQuantize * quant,
/* store result */
d[i] = v;
}
memmove (e, &e[len], sizeof (gint32) * channels * nc);
memmove (e, &e[len], sizeof (gint32) * stride * nc);
}
#define MAKE_QUANTIZE_FUNC_NAME(name) \
@ -355,7 +356,7 @@ gst_audio_quantize_setup_noise_shaping (GstAudioQuantize * quant)
if (n_coeffs) {
quant->n_coeffs = n_coeffs;
q = quant->coeffs = g_new0 (gint32, quant->channels * n_coeffs);
q = quant->coeffs = g_new0 (gint32, n_coeffs);
for (i = 0; i < n_coeffs; i++)
q[i] = floor (coeffs[i] * (1 << SHIFT) + 0.5);
}
@ -367,7 +368,7 @@ gst_audio_quantize_setup_dither (GstAudioQuantize * quant)
{
switch (quant->dither) {
case GST_AUDIO_DITHER_TPDF_HF:
quant->last_random = g_new0 (gint32, quant->channels);
quant->last_random = g_new0 (gint32, quant->stride);
break;
case GST_AUDIO_DITHER_RPDF:
case GST_AUDIO_DITHER_TPDF:
@ -440,7 +441,13 @@ gst_audio_quantize_new (GstAudioDitherMethod dither,
quant->ns = ns;
quant->flags = flags;
quant->format = format;
quant->channels = channels;
if (flags & GST_AUDIO_QUANTIZE_FLAG_NON_INTERLEAVED) {
quant->stride = 1;
quant->blocks = channels;
} else {
quant->stride = channels;
quant->blocks = 1;
}
quant->quantizer = quantizer;
quant->shift = count_power (quantizer);
@ -479,22 +486,31 @@ gst_audio_quantize_free (GstAudioQuantize * quant)
/**
* gst_audio_quantize_samples:
* @quant: a #GstAudioQuantize
* @src: source samples
* @dst: output samples
* @in: input samples
* @out: output samples
* @samples: number of samples
*
* Perform quantization on @samples in @src and write the result to @dst.
* Perform quantization on @samples in @in and write the result to @out.
*
* @src and @dst may point to the same memory location, in which case samples will be
* In case the samples are interleaved, @in and @out must point to an
* array with a single element pointing to a block of interleaved samples.
*
* If non-interleaved samples are used, @in and @out must point to an
* array with pointers to memory blocks, one for each channel.
*
* @in and @out may point to the same memory location, in which case samples will be
* modified in-place.
*/
void
gst_audio_quantize_samples (GstAudioQuantize * quant,
const gpointer src, gpointer dst, guint samples)
const gpointer in[], gpointer out[], guint samples)
{
g_return_if_fail (quant != NULL);
g_return_if_fail (dst != NULL || samples == 0);
g_return_if_fail (src != NULL || samples == 0);
guint i;
quant->quantize (quant, dst, src, samples);
g_return_if_fail (quant != NULL);
g_return_if_fail (out != NULL || samples == 0);
g_return_if_fail (in != NULL || samples == 0);
for (i = 0; i < quant->blocks; i++)
quant->quantize (quant, in[i], out[i], samples);
}

View file

@ -91,7 +91,7 @@ GstAudioQuantize * gst_audio_quantize_new (GstAudioDitherMethod dither,
void gst_audio_quantize_free (GstAudioQuantize * quant);
void gst_audio_quantize_samples (GstAudioQuantize * quant,
const gpointer src,
gpointer dst, guint samples);
const gpointer in[],
gpointer out[], guint samples);
#endif /* __GST_AUDIO_QUANTIZE_H__ */

View file

@ -735,8 +735,9 @@ gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
flags |= GST_AUDIO_CONVERTER_FLAG_SOURCE_WRITABLE;
if (!GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) {
if (!gst_audio_converter_samples (this->convert, flags, srcmap.data,
samples, dstmap.data, samples, &consumed, &produced))
if (!gst_audio_converter_samples (this->convert, flags,
(gpointer *) & srcmap.data, samples, (gpointer *) & dstmap.data,
samples, &consumed, &produced))
goto convert_error;
} else {
/* Create silence buffer */