#define ensure_debug_category() /* NOOP */
#endif /* GST_DISABLE_GST_DEBUG */
-typedef void (*AudioConvertFunc) (gpointer dst, const gpointer src, gint count);
+typedef struct _AudioChain AudioChain;
+typedef void (*AudioConvertFunc) (gpointer dst, const gpointer src, gint count);
/* int/int int/float float/int float/float
*
* unpack S32 S32 F64 F64
* convert F64->S32
* quantize S32 S32
* pack S32 F64 S32 F64
+ *
+ *
+ * interleave
+ * deinterleave
+ * resample
*/
struct _GstAudioConverter
{
GstStructure *config;
+ GstAudioConverterFlags flags;
+ GstAudioFormat current_format;
+ GstAudioLayout current_layout;
+ gint current_channels;
+
+ gpointer *in_data;
+ gpointer *out_data;
+
+ /* unpack */
gboolean in_default;
+ gboolean unpack_ip;
+ AudioChain *unpack_chain;
+ /* convert in */
AudioConvertFunc convert_in;
+ AudioChain *convert_in_chain;
+ /* channel mix */
gboolean mix_passthrough;
GstAudioChannelMix *mix;
+ AudioChain *mix_chain;
+ /* convert out */
AudioConvertFunc convert_out;
+ AudioChain *convert_out_chain;
+ /* quant */
GstAudioQuantize *quant;
+ AudioChain *quant_chain;
+ /* pack */
gboolean out_default;
+ AudioChain *pack_chain;
gboolean passthrough;
+};
+
+typedef gboolean (*AudioChainFunc) (AudioChain * chain, gsize samples,
+ gpointer user_data);
+typedef gpointer *(*AudioChainAllocFunc) (AudioChain * chain, gsize samples,
+ gpointer user_data);
+
+static gpointer *get_output_samples (AudioChain * chain, gsize samples,
+ gpointer user_data);
+
+struct _AudioChain
+{
+ AudioChain *prev;
- gpointer tmpbuf;
- gpointer tmpbuf2;
- gint tmpbufsize;
+ AudioChainFunc make_func;
+ gpointer make_func_data;
+ GDestroyNotify make_func_notify;
+
+ gint stride;
+ gint inc;
+ gint blocks;
+
+ gboolean pass_alloc;
+ gboolean allow_ip;
+
+ AudioChainAllocFunc alloc_func;
+ gpointer alloc_data;
+
+ gpointer *tmp;
+ gsize tmpsize;
+
+ gpointer *samples;
};
+static AudioChain *
+audio_chain_new (AudioChain * prev, GstAudioConverter * convert)
+{
+ AudioChain *chain;
+ const GstAudioFormatInfo *finfo;
+
+ chain = g_slice_new0 (AudioChain);
+ chain->prev = prev;
+
+ if (convert->current_layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
+ chain->inc = 1;
+ chain->blocks = convert->current_channels;
+ } else {
+ chain->inc = convert->current_channels;
+ chain->blocks = 1;
+ }
+ finfo = gst_audio_format_get_info (convert->current_format);
+ chain->stride = (finfo->width * chain->inc) / 8;
+
+ return chain;
+}
+
+static void
+audio_chain_set_make_func (AudioChain * chain,
+ AudioChainFunc make_func, gpointer user_data, GDestroyNotify notify)
+{
+ chain->make_func = make_func;
+ chain->make_func_data = user_data;
+ chain->make_func_notify = notify;
+}
+
+static void
+audio_chain_free (AudioChain * chain)
+{
+ GST_LOG ("free chain %p", chain);
+ if (chain->make_func_notify)
+ chain->make_func_notify (chain->make_func_data);
+ g_free (chain->tmp);
+ g_slice_free (AudioChain, chain);
+}
+
+static gpointer *
+audio_chain_alloc_samples (AudioChain * chain, guint samples)
+{
+ return chain->alloc_func (chain, samples, chain->alloc_data);
+}
+
+static gpointer *
+audio_chain_get_samples (AudioChain * chain, guint samples)
+{
+ gpointer *res;
+
+ while (!chain->samples)
+ chain->make_func (chain, samples, chain->make_func_data);
+
+ res = chain->samples;
+ chain->samples = NULL;
+
+ return res;
+}
+
/*
static guint
get_opt_uint (GstAudioConverter * convert, const gchar * opt, guint def)
return convert->config;
}
-/**
- * gst_audio_converter_new: (skip)
- * @in: a source #GstAudioInfo
- * @out: a destination #GstAudioInfo
- * @config: (transfer full): a #GstStructure with configuration options
- *
- * Create a new #GstAudioConverter that is able to convert between @in and @out
- * audio formats.
- *
- * @config contains extra configuration options, see #GST_VIDEO_CONVERTER_OPT_*
- * parameters for details about the options and values.
- *
- * Returns: a #GstAudioConverter or %NULL if conversion is not possible.
- */
-GstAudioConverter *
-gst_audio_converter_new (GstAudioInfo * in, GstAudioInfo * out,
- GstStructure * config)
+static gboolean
+do_unpack (AudioChain * chain, gsize samples, gpointer user_data)
{
- GstAudioConverter *convert;
- gint in_depth, out_depth;
- GstAudioChannelMixFlags flags;
- gboolean in_int, out_int;
- GstAudioFormat format;
- GstAudioDitherMethod dither;
- GstAudioNoiseShapingMethod ns;
+ GstAudioConverter *convert = user_data;
+ gpointer *tmp;
+ gboolean src_writable;
- g_return_val_if_fail (in != NULL, FALSE);
- g_return_val_if_fail (out != NULL, FALSE);
- g_return_val_if_fail (in->rate == out->rate, FALSE);
- g_return_val_if_fail (in->layout == GST_AUDIO_LAYOUT_INTERLEAVED, FALSE);
- g_return_val_if_fail (in->layout == out->layout, FALSE);
+ src_writable = (convert->flags & GST_AUDIO_CONVERTER_FLAG_SOURCE_WRITABLE);
- if ((GST_AUDIO_INFO_CHANNELS (in) != GST_AUDIO_INFO_CHANNELS (out)) &&
- (GST_AUDIO_INFO_IS_UNPOSITIONED (in)
- || GST_AUDIO_INFO_IS_UNPOSITIONED (out)))
- goto unpositioned;
+ if (!chain->allow_ip || !src_writable || !convert->in_default) {
+ gint i;
- convert = g_slice_new0 (GstAudioConverter);
+ if (src_writable && chain->allow_ip)
+ tmp = convert->in_data;
+ else
+ tmp = audio_chain_alloc_samples (chain, samples);
+ GST_LOG ("unpack %p %p, %" G_GSIZE_FORMAT, tmp, convert->in_data, samples);
+
+ for (i = 0; i < chain->blocks; i++) {
+ convert->in.finfo->unpack_func (convert->in.finfo,
+ GST_AUDIO_PACK_FLAG_TRUNCATE_RANGE, tmp[i], convert->in_data[i],
+ samples * chain->inc);
+ }
+ } else {
+ tmp = convert->in_data;
+ GST_LOG ("get in samples %p", tmp);
+ }
+ chain->samples = tmp;
- convert->in = *in;
- convert->out = *out;
+ return TRUE;
+}
- /* default config */
- convert->config = gst_structure_new_empty ("GstAudioConverter");
- if (config)
- gst_audio_converter_set_config (convert, config);
+static gboolean
+do_convert_in (AudioChain * chain, gsize samples, gpointer user_data)
+{
+ GstAudioConverter *convert = user_data;
+ gpointer *in, *out;
+ gint i;
- dither = GET_OPT_DITHER_METHOD (convert);
- ns = GET_OPT_NOISE_SHAPING_METHOD (convert);
+ in = audio_chain_get_samples (chain->prev, samples);
+ out = (chain->allow_ip ? in : audio_chain_alloc_samples (chain, samples));
+ GST_LOG ("convert in %p, %p %" G_GSIZE_FORMAT, in, out, samples);
- GST_INFO ("unitsizes: %d -> %d", in->bpf, out->bpf);
+ for (i = 0; i < chain->blocks; i++)
+ convert->convert_in (out[i], in[i], samples * chain->inc);
- in_depth = GST_AUDIO_FORMAT_INFO_DEPTH (in->finfo);
- out_depth = GST_AUDIO_FORMAT_INFO_DEPTH (out->finfo);
+ chain->samples = out;
- GST_INFO ("depth in %d, out %d", in_depth, out_depth);
+ return TRUE;
+}
- in_int = GST_AUDIO_FORMAT_INFO_IS_INTEGER (in->finfo);
- out_int = GST_AUDIO_FORMAT_INFO_IS_INTEGER (out->finfo);
+static gboolean
+do_mix (AudioChain * chain, gsize samples, gpointer user_data)
+{
+ GstAudioConverter *convert = user_data;
+ gpointer *in, *out;
- flags =
- GST_AUDIO_INFO_IS_UNPOSITIONED (in) ?
- GST_AUDIO_CHANNEL_MIX_FLAGS_UNPOSITIONED_IN : 0;
- flags |=
- GST_AUDIO_INFO_IS_UNPOSITIONED (out) ?
- GST_AUDIO_CHANNEL_MIX_FLAGS_UNPOSITIONED_OUT : 0;
+ in = audio_chain_get_samples (chain->prev, samples);
+ out = (chain->allow_ip ? in : audio_chain_alloc_samples (chain, samples));
+ GST_LOG ("mix %p %p,%" G_GSIZE_FORMAT, in, out, samples);
+ gst_audio_channel_mix_samples (convert->mix, in, out, samples);
- /* step 1, unpack */
- format = in->finfo->unpack_format;
+ chain->samples = out;
+
+ return TRUE;
+}
+
+static gboolean
+do_convert_out (AudioChain * chain, gsize samples, gpointer user_data)
+{
+ GstAudioConverter *convert = user_data;
+ gpointer *in, *out;
+ gint i;
+
+ in = audio_chain_get_samples (chain->prev, samples);
+ out = (chain->allow_ip ? in : audio_chain_alloc_samples (chain, samples));
+ GST_LOG ("convert out %p, %p %" G_GSIZE_FORMAT, in, out, samples);
+
+ for (i = 0; i < chain->blocks; i++)
+ convert->convert_out (out[i], in[i], samples * chain->inc);
+
+ chain->samples = out;
+
+ return TRUE;
+}
+
+static gboolean
+do_quantize (AudioChain * chain, gsize samples, gpointer user_data)
+{
+ GstAudioConverter *convert = user_data;
+ gpointer *in, *out;
+
+ in = audio_chain_get_samples (chain->prev, samples);
+ out = (chain->allow_ip ? in : audio_chain_alloc_samples (chain, samples));
+ GST_LOG ("quantize %p, %p %" G_GSIZE_FORMAT, in, out, samples);
+
+ gst_audio_quantize_samples (convert->quant, in, out, samples);
+
+ chain->samples = out;
+
+ return TRUE;
+}
+
+static AudioChain *
+chain_unpack (GstAudioConverter * convert)
+{
+ AudioChain *prev;
+ GstAudioInfo *in = &convert->in;
+ const GstAudioFormatInfo *fup;
+
+ convert->current_format = in->finfo->unpack_format;
+ convert->current_layout = in->layout;
+ convert->current_channels = in->channels;
convert->in_default = in->finfo->unpack_format == in->finfo->format;
+
GST_INFO ("unpack format %s to %s",
gst_audio_format_to_string (in->finfo->format),
- gst_audio_format_to_string (format));
+ gst_audio_format_to_string (convert->current_format));
+
+ fup = gst_audio_format_get_info (in->finfo->unpack_format);
+
+ prev = convert->unpack_chain = audio_chain_new (NULL, convert);
+ prev->allow_ip = fup->width <= in->finfo->width;
+ prev->pass_alloc = FALSE;
+ audio_chain_set_make_func (prev, do_unpack, convert, NULL);
+
+ return prev;
+}
+
+static AudioChain *
+chain_convert_in (GstAudioConverter * convert, AudioChain * prev)
+{
+ gboolean in_int, out_int;
+ GstAudioInfo *in = &convert->in;
+ GstAudioInfo *out = &convert->out;
+
+ in_int = GST_AUDIO_FORMAT_INFO_IS_INTEGER (in->finfo);
+ out_int = GST_AUDIO_FORMAT_INFO_IS_INTEGER (out->finfo);
- /* step 2, optional convert from S32 to F64 for channel mix */
if (in_int && !out_int) {
GST_INFO ("convert S32 to F64");
convert->convert_in = (AudioConvertFunc) audio_orc_s32_to_double;
- format = GST_AUDIO_FORMAT_F64;
+ convert->current_format = GST_AUDIO_FORMAT_F64;
+
+ prev = convert->convert_in_chain = audio_chain_new (prev, convert);
+ prev->allow_ip = FALSE;
+ prev->pass_alloc = FALSE;
+ audio_chain_set_make_func (prev, do_convert_in, convert, NULL);
}
+ return prev;
+}
+
+static AudioChain *
+chain_mix (GstAudioConverter * convert, AudioChain * prev)
+{
+ GstAudioChannelMixFlags flags;
+ GstAudioInfo *in = &convert->in;
+ GstAudioInfo *out = &convert->out;
+ GstAudioFormat format = convert->current_format;
+
+ flags =
+ GST_AUDIO_INFO_IS_UNPOSITIONED (in) ?
+ GST_AUDIO_CHANNEL_MIX_FLAGS_UNPOSITIONED_IN : 0;
+ flags |=
+ GST_AUDIO_INFO_IS_UNPOSITIONED (out) ?
+ GST_AUDIO_CHANNEL_MIX_FLAGS_UNPOSITIONED_OUT : 0;
+
+ convert->current_channels = out->channels;
- /* step 3, channel mix */
convert->mix =
gst_audio_channel_mix_new (flags, format, in->channels, in->position,
out->channels, out->position);
gst_audio_format_to_string (format), convert->mix_passthrough,
in->channels, out->channels);
- /* step 4, optional convert for quantize */
+ if (!convert->mix_passthrough) {
+ prev = convert->mix_chain = audio_chain_new (prev, convert);
+ /* we can only do in-place when in >= out, else we don't have enough
+ * memory. */
+ prev->allow_ip = in->channels >= out->channels;
+ prev->pass_alloc = in->channels <= out->channels;
+ audio_chain_set_make_func (prev, do_mix, convert, NULL);
+ }
+ return prev;
+}
+
+static AudioChain *
+chain_convert_out (GstAudioConverter * convert, AudioChain * prev)
+{
+ gboolean in_int, out_int;
+ GstAudioInfo *in = &convert->in;
+ GstAudioInfo *out = &convert->out;
+
+ in_int = GST_AUDIO_FORMAT_INFO_IS_INTEGER (in->finfo);
+ out_int = GST_AUDIO_FORMAT_INFO_IS_INTEGER (out->finfo);
+
if (!in_int && out_int) {
- GST_INFO ("convert F64 to S32");
convert->convert_out = (AudioConvertFunc) audio_orc_double_to_s32;
- format = GST_AUDIO_FORMAT_S32;
+ convert->current_format = GST_AUDIO_FORMAT_S32;
+
+ GST_INFO ("convert F64 to S32");
+ prev = convert->convert_out_chain = audio_chain_new (prev, convert);
+ prev->allow_ip = TRUE;
+ prev->pass_alloc = FALSE;
+ audio_chain_set_make_func (prev, do_convert_out, convert, NULL);
}
- /* step 5, optional quantize */
+ return prev;
+}
+
+static AudioChain *
+chain_quantize (GstAudioConverter * convert, AudioChain * prev)
+{
+ GstAudioInfo *in = &convert->in;
+ GstAudioInfo *out = &convert->out;
+ gint in_depth, out_depth;
+ gboolean in_int, out_int;
+ GstAudioDitherMethod dither;
+ GstAudioNoiseShapingMethod ns;
+
+ dither = GET_OPT_DITHER_METHOD (convert);
+ ns = GET_OPT_NOISE_SHAPING_METHOD (convert);
+
+ in_depth = GST_AUDIO_FORMAT_INFO_DEPTH (in->finfo);
+ out_depth = GST_AUDIO_FORMAT_INFO_DEPTH (out->finfo);
+ GST_INFO ("depth in %d, out %d", in_depth, out_depth);
+
+ in_int = GST_AUDIO_FORMAT_INFO_IS_INTEGER (in->finfo);
+ out_int = GST_AUDIO_FORMAT_INFO_IS_INTEGER (out->finfo);
+
/* Don't dither or apply noise shaping if target depth is bigger than 20 bits
* as DA converters only can do a SNR up to 20 bits in reality.
* Also don't dither or apply noise shaping if target depth is larger than
* the rounding correct */
if (out_int && out_depth < 32) {
GST_INFO ("quantize to %d bits, dither %d, ns %d", out_depth, dither, ns);
- convert->quant = gst_audio_quantize_new (dither, ns, 0, format,
+ convert->quant =
+ gst_audio_quantize_new (dither, ns, 0, convert->current_format,
out->channels, 1U << (32 - out_depth));
+
+ prev = convert->quant_chain = audio_chain_new (prev, convert);
+ prev->allow_ip = TRUE;
+ prev->pass_alloc = TRUE;
+ audio_chain_set_make_func (prev, do_quantize, convert, NULL);
}
- /* step 6, pack */
+ return prev;
+}
+
+static AudioChain *
+chain_pack (GstAudioConverter * convert, AudioChain * prev)
+{
+ GstAudioInfo *out = &convert->out;
+ GstAudioFormat format = convert->current_format;
+
+ convert->current_format = out->finfo->format;
+
g_assert (out->finfo->unpack_format == format);
convert->out_default = format == out->finfo->format;
GST_INFO ("pack format %s to %s", gst_audio_format_to_string (format),
gst_audio_format_to_string (out->finfo->format));
+ return prev;
+}
+
+static gpointer *
+get_output_samples (AudioChain * chain, gsize samples, gpointer user_data)
+{
+ GstAudioConverter *convert = user_data;
+
+ GST_LOG ("output samples %" G_GSIZE_FORMAT, samples);
+ return convert->out_data;
+}
+
+static gpointer *
+get_temp_samples (AudioChain * chain, gsize samples, gpointer user_data)
+{
+ gsize needed;
+
+ /* first part contains the pointers, second part the data */
+ needed = (samples * chain->stride + sizeof (gpointer)) * chain->blocks;
+
+ if (needed > chain->tmpsize) {
+ gint i;
+ guint8 *s;
+
+ GST_DEBUG ("alloc samples %" G_GSIZE_FORMAT, needed);
+ chain->tmp = g_realloc (chain->tmp, needed);
+ chain->tmpsize = needed;
+
+ /* jump to the data */
+ s = (guint8 *) & chain->tmp[chain->blocks];
+
+ /* set up the pointers */
+ for (i = 0; i < chain->blocks; i++)
+ chain->tmp[i] = s + (i * samples * chain->stride);
+ }
+ return chain->tmp;
+}
+
+static void
+setup_allocators (GstAudioConverter * convert)
+{
+ AudioChain *chain;
+ AudioChainAllocFunc alloc_func;
+ gboolean allow_ip;
+
+ /* start with using dest if we can directly write into it */
+ if (convert->out_default) {
+ alloc_func = get_output_samples;
+ allow_ip = FALSE;
+ } else {
+ alloc_func = get_temp_samples;
+ allow_ip = TRUE;
+ }
+ /* now walk backwards, we try to write into the dest samples directly
+ * and keep track if the source needs to be writable */
+ for (chain = convert->pack_chain; chain; chain = chain->prev) {
+ chain->alloc_func = alloc_func;
+ chain->alloc_data = convert;
+ chain->allow_ip = allow_ip && chain->allow_ip;
+
+ if (!chain->pass_alloc) {
+ /* can't pass allocator, make new temp line allocator */
+ alloc_func = get_temp_samples;
+ allow_ip = TRUE;
+ }
+ }
+}
+
+/**
+ * gst_audio_converter_new: (skip)
+ * @in: a source #GstAudioInfo
+ * @out: a destination #GstAudioInfo
+ * @config: (transfer full): a #GstStructure with configuration options
+ *
+ * Create a new #GstAudioConverter that is able to convert between @in and @out
+ * audio formats.
+ *
+ * @config contains extra configuration options, see #GST_VIDEO_CONVERTER_OPT_*
+ * parameters for details about the options and values.
+ *
+ * Returns: a #GstAudioConverter or %NULL if conversion is not possible.
+ */
+GstAudioConverter *
+gst_audio_converter_new (GstAudioInfo * in, GstAudioInfo * out,
+ GstStructure * config)
+{
+ GstAudioConverter *convert;
+ AudioChain *prev;
+
+ g_return_val_if_fail (in != NULL, FALSE);
+ g_return_val_if_fail (out != NULL, FALSE);
+ g_return_val_if_fail (in->rate == out->rate, FALSE);
+ g_return_val_if_fail (in->layout == GST_AUDIO_LAYOUT_INTERLEAVED, FALSE);
+ g_return_val_if_fail (in->layout == out->layout, FALSE);
+
+ if ((GST_AUDIO_INFO_CHANNELS (in) != GST_AUDIO_INFO_CHANNELS (out)) &&
+ (GST_AUDIO_INFO_IS_UNPOSITIONED (in)
+ || GST_AUDIO_INFO_IS_UNPOSITIONED (out)))
+ goto unpositioned;
+
+ convert = g_slice_new0 (GstAudioConverter);
+
+ convert->in = *in;
+ convert->out = *out;
+
+ /* default config */
+ convert->config = gst_structure_new_empty ("GstAudioConverter");
+ if (config)
+ gst_audio_converter_set_config (convert, config);
+
+ GST_INFO ("unitsizes: %d -> %d", in->bpf, out->bpf);
+
+ /* step 1, unpack */
+ prev = chain_unpack (convert);
+ /* step 2, optional convert from S32 to F64 for channel mix */
+ prev = chain_convert_in (convert, prev);
+ /* step 3, channel mix */
+ prev = chain_mix (convert, prev);
+ /* step 4, optional convert for quantize */
+ prev = chain_convert_out (convert, prev);
+ /* step 5, optional quantize */
+ prev = chain_quantize (convert, prev);
+ /* step 6, pack */
+ convert->pack_chain = chain_pack (convert, prev);
+
/* optimize */
if (out->finfo->format == in->finfo->format && convert->mix_passthrough) {
GST_INFO ("same formats and passthrough mixing -> passthrough");
convert->passthrough = TRUE;
}
+ setup_allocators (convert);
+
+
return convert;
/* ERRORS */
{
g_return_if_fail (convert != NULL);
+ if (convert->unpack_chain)
+ audio_chain_free (convert->unpack_chain);
+ if (convert->convert_in_chain)
+ audio_chain_free (convert->convert_in_chain);
+ if (convert->mix_chain)
+ audio_chain_free (convert->mix_chain);
+ if (convert->convert_out_chain)
+ audio_chain_free (convert->convert_out_chain);
+ if (convert->quant_chain)
+ audio_chain_free (convert->quant_chain);
+
if (convert->quant)
gst_audio_quantize_free (convert->quant);
if (convert->mix)
gst_audio_info_init (&convert->in);
gst_audio_info_init (&convert->out);
- g_free (convert->tmpbuf);
- g_free (convert->tmpbuf2);
gst_structure_free (convert->config);
g_slice_free (GstAudioConverter, convert);
}
/**
+ * gst_audio_converter_get_out_frames:
+ * @convert: a #GstAudioConverter
+ * @in_frames: number of input frames
+ *
+ * Calculate how many output frames can be produced when @in_frames input
+ * frames are given to @convert.
+ *
+ * Returns: the number of output frames
+ */
+gsize
+gst_audio_converter_get_out_frames (GstAudioConverter * convert,
+ gsize in_frames)
+{
+ return in_frames;
+}
+
+/**
+ * gst_audio_converter_get_in_frames:
+ * @convert: a #GstAudioConverter
+ * @out_frames: number of output frames
+ *
+ * Calculate how many input frames are currently needed by @convert to produce
+ * @out_frames of output frames.
+ *
+ * Returns: the number of input frames
+ */
+gsize
+gst_audio_converter_get_in_frames (GstAudioConverter * convert,
+ gsize out_frames)
+{
+ return out_frames;
+}
+
+/**
+ * gst_audio_converter_get_max_latency:
+ * @convert: a #GstAudioConverter
+ *
+ * Get the maximum number of input frames that the converter would
+ * need before producing output.
+ *
+ * Returns: the latency of @convert as expressed in the number of
+ * frames.
+ */
+gsize
+gst_audio_converter_get_max_latency (GstAudioConverter * convert)
+{
+ return 0;
+}
+
+/**
* gst_audio_converter_samples:
* @convert: a #GstAudioConverter
* @flags: extra #GstAudioConverterFlags
gpointer out[], gsize out_samples, gsize * in_consumed,
gsize * out_produced)
{
- guint size;
- gpointer outbuf, tmpbuf, tmpbuf2, inp, outp;
+ AudioChain *chain;
+ gpointer *tmp;
+ gint i;
g_return_val_if_fail (convert != NULL, FALSE);
g_return_val_if_fail (in != NULL, FALSE);
return TRUE;
}
- inp = in[0];
- outp = out[0];
+ chain = convert->pack_chain;
if (convert->passthrough) {
- memcpy (outp, inp, in_samples * convert->in.bpf);
+ for (i = 0; i < chain->blocks; i++)
+ memcpy (out[i], in[i], in_samples * chain->inc);
*out_produced = in_samples;
*in_consumed = in_samples;
return TRUE;
}
- size =
- sizeof (gdouble) * in_samples * MAX (convert->in.channels,
- convert->out.channels);
-
- if (size > convert->tmpbufsize) {
- convert->tmpbuf = g_realloc (convert->tmpbuf, size);
- convert->tmpbuf2 = g_realloc (convert->tmpbuf2, size);
- convert->tmpbufsize = size;
- }
- tmpbuf = convert->tmpbuf;
- tmpbuf2 = convert->tmpbuf2;
-
- /* 1. unpack */
- if (!convert->in_default) {
- if (!convert->convert_in && convert->mix_passthrough
- && !convert->convert_out && !convert->quant && convert->out_default)
- outbuf = outp;
- else
- outbuf = tmpbuf;
-
- convert->in.finfo->unpack_func (convert->in.finfo,
- GST_AUDIO_PACK_FLAG_TRUNCATE_RANGE, outbuf, inp,
- in_samples * convert->in.channels);
- inp = outbuf;
- }
-
- /* 2. optionally convert for mixing */
- if (convert->convert_in) {
- if (convert->mix_passthrough && !convert->convert_out && !convert->quant
- && convert->out_default)
- outbuf = outp;
- else if (inp == tmpbuf)
- outbuf = tmpbuf2;
- else
- outbuf = tmpbuf;
-
- convert->convert_in (outbuf, inp, in_samples * convert->in.channels);
- inp = outbuf;
- }
-
- /* step 3, channel mix if not passthrough */
- if (!convert->mix_passthrough) {
- if (!convert->convert_out && !convert->quant && convert->out_default)
- outbuf = outp;
- else
- outbuf = tmpbuf;
-
- gst_audio_channel_mix_samples (convert->mix, &inp, &outbuf, in_samples);
- inp = outbuf;
- }
- /* step 4, optional convert F64 -> S32 for quantize */
- if (convert->convert_out) {
- if (!convert->quant && convert->out_default)
- outbuf = outp;
- else
- outbuf = tmpbuf;
-
- convert->convert_out (outbuf, inp, in_samples * convert->out.channels);
- inp = outbuf;
- }
-
- /* step 5, optional quantize */
- if (convert->quant) {
- if (convert->out_default)
- outbuf = outp;
- else
- outbuf = tmpbuf;
+ convert->flags = flags;
+ convert->in_data = in;
+ convert->out_data = out;
- gst_audio_quantize_samples (convert->quant, &inp, &outbuf, in_samples);
- inp = outbuf;
- }
+ /* get samples to pack */
+ tmp = audio_chain_get_samples (chain, in_samples);
- /* step 6, pack */
if (!convert->out_default) {
- convert->out.finfo->pack_func (convert->out.finfo, 0, inp, outp,
- in_samples * convert->out.channels);
+ GST_LOG ("pack %p, %p %" G_GSIZE_FORMAT, tmp, out, in_samples);
+ /* and pack if needed */
+ for (i = 0; i < chain->blocks; i++)
+ convert->out.finfo->pack_func (convert->out.finfo, 0, tmp[i], out[i],
+ in_samples * chain->inc);
}
+
*out_produced = in_samples;
*in_consumed = in_samples;