audio-converter: simplify API

Remove the consumed/produced output fields from the resampler and
converter. Let the caler specify the right number of input/output
samples so we can be more optimal.
Use just one function to update the converter configuration.
Simplify some things internally.
Make it possible to use writable input as temp space in audioconvert.
This commit is contained in:
Wim Taymans 2016-01-05 16:06:22 +01:00
parent 1d9a793545
commit de37491662
5 changed files with 79 additions and 164 deletions

View file

@ -217,19 +217,16 @@ audio_chain_free (AudioChain * chain)
} }
static gpointer * static gpointer *
audio_chain_alloc_samples (AudioChain * chain, gsize num_samples, gsize * avail) audio_chain_alloc_samples (AudioChain * chain, gsize num_samples)
{ {
return chain->alloc_func (chain, num_samples, avail, chain->alloc_data); return chain->alloc_func (chain, num_samples, chain->alloc_data);
} }
static void static void
audio_chain_set_samples (AudioChain * chain, gpointer * samples, audio_chain_set_samples (AudioChain * chain, gpointer * samples,
gsize num_samples) gsize num_samples)
{ {
if (num_samples == 0) GST_LOG ("set samples %p %" G_GSIZE_FORMAT, samples, num_samples);
return;
GST_LOG ("set samples %" G_GSIZE_FORMAT, num_samples);
chain->samples = samples; chain->samples = samples;
chain->num_samples = num_samples; chain->num_samples = num_samples;
@ -307,7 +304,7 @@ copy_config (GQuark field_id, const GValue * value, gpointer user_data)
* *
* Set @in_rate, @out_rate and @config as extra configuration for @convert. * Set @in_rate, @out_rate and @config as extra configuration for @convert.
* *
* in_rate and @out_rate specify the new sample rates of input and output * @in_rate and @out_rate specify the new sample rates of input and output
* formats. A value of 0 leaves the sample rate unchanged. * formats. A value of 0 leaves the sample rate unchanged.
* *
* @config can be %NULL, in which case, the current configuration is not * @config can be %NULL, in which case, the current configuration is not
@ -345,6 +342,10 @@ gst_audio_converter_update_config (GstAudioConverter * convert,
gst_structure_free (config); gst_structure_free (config);
} }
if (convert->resampler)
gst_audio_resampler_update (convert->resampler, in_rate, out_rate,
convert->config);
return TRUE; return TRUE;
} }
@ -459,7 +460,6 @@ do_unpack (AudioChain * chain, gpointer user_data)
} }
} else { } else {
tmp = convert->in_data; tmp = convert->in_data;
num_samples = convert->in_samples;
GST_LOG ("get in samples %p", tmp); GST_LOG ("get in samples %p", tmp);
} }
audio_chain_set_samples (chain, tmp, num_samples); audio_chain_set_samples (chain, tmp, num_samples);
@ -470,8 +470,8 @@ do_unpack (AudioChain * chain, gpointer user_data)
static gboolean static gboolean
do_convert_in (AudioChain * chain, gpointer user_data) do_convert_in (AudioChain * chain, gpointer user_data)
{ {
GstAudioConverter *convert = user_data;
gsize num_samples; gsize num_samples;
GstAudioConverter *convert = user_data;
gpointer *in, *out; gpointer *in, *out;
gint i; gint i;
@ -490,8 +490,8 @@ do_convert_in (AudioChain * chain, gpointer user_data)
static gboolean static gboolean
do_mix (AudioChain * chain, gpointer user_data) do_mix (AudioChain * chain, gpointer user_data)
{ {
GstAudioConverter *convert = user_data;
gsize num_samples; gsize num_samples;
GstAudioConverter *convert = user_data;
gpointer *in, *out; gpointer *in, *out;
in = audio_chain_get_samples (chain->prev, &num_samples); in = audio_chain_get_samples (chain->prev, &num_samples);
@ -510,23 +510,19 @@ do_resample (AudioChain * chain, gpointer user_data)
{ {
GstAudioConverter *convert = user_data; GstAudioConverter *convert = user_data;
gpointer *in, *out; gpointer *in, *out;
gsize in_frames, out_frames, produced, consumed; gsize in_frames, out_frames;
in = audio_chain_get_samples (chain->prev, &in_frames); in = audio_chain_get_samples (chain->prev, &in_frames);
out_frames = convert->out_samples;
out = (chain->allow_ip ? in : audio_chain_alloc_samples (chain, out_frames));
out_frames = GST_LOG ("resample %p %p,%" G_GSIZE_FORMAT " %" G_GSIZE_FORMAT, in,
gst_audio_resampler_get_out_frames (convert->resampler, in_frames); out, in_frames, out_frames);
out =
(chain->allow_ip ? in : audio_chain_alloc_samples (chain, out_frames,
&out_frames));
GST_LOG ("resample %p %p,%" G_GSIZE_FORMAT " %" G_GSIZE_FORMAT " %"
G_GSIZE_FORMAT, in, out, in_frames, out_frames, num_samples);
gst_audio_resampler_resample (convert->resampler, in, in_frames, out, gst_audio_resampler_resample (convert->resampler, in, in_frames, out,
out_frames, &consumed, &produced); out_frames);
audio_chain_set_samples (chain, out, produced); audio_chain_set_samples (chain, out, out_frames);
return TRUE; return TRUE;
} }
@ -541,7 +537,7 @@ do_convert_out (AudioChain * chain, gpointer user_data)
in = audio_chain_get_samples (chain->prev, &num_samples); in = audio_chain_get_samples (chain->prev, &num_samples);
out = (chain->allow_ip ? in : audio_chain_alloc_samples (chain, num_samples)); out = (chain->allow_ip ? in : audio_chain_alloc_samples (chain, num_samples));
GST_LOG ("convert out %p, %p, %" G_GSIZE_FORMAT, in, out, num_samples); GST_LOG ("convert out %p, %p %" G_GSIZE_FORMAT, in, out, num_samples);
for (i = 0; i < chain->blocks; i++) for (i = 0; i < chain->blocks; i++)
convert->convert_out (out[i], in[i], num_samples * chain->inc); convert->convert_out (out[i], in[i], num_samples * chain->inc);
@ -560,7 +556,7 @@ do_quantize (AudioChain * chain, gpointer user_data)
in = audio_chain_get_samples (chain->prev, &num_samples); in = audio_chain_get_samples (chain->prev, &num_samples);
out = (chain->allow_ip ? in : audio_chain_alloc_samples (chain, num_samples)); out = (chain->allow_ip ? in : audio_chain_alloc_samples (chain, num_samples));
GST_LOG ("quantize %p, %p, %" G_GSIZE_FORMAT, in, out, num_samples); GST_LOG ("quantize %p, %p %" G_GSIZE_FORMAT, in, out, num_samples);
gst_audio_quantize_samples (convert->quant, in, out, num_samples); gst_audio_quantize_samples (convert->quant, in, out, num_samples);
@ -679,7 +675,8 @@ chain_resample (GstAudioConverter * convert, AudioChain * prev)
GstAudioFormat format = convert->current_format; GstAudioFormat format = convert->current_format;
gint channels = convert->current_channels; gint channels = convert->current_channels;
if (in->rate != out->rate) { if (in->rate != out->rate
|| convert->flags & GST_AUDIO_CONVERTER_FLAG_VARIABLE_RATE) {
method = GET_OPT_RESAMPLER_METHOD (convert); method = GET_OPT_RESAMPLER_METHOD (convert);
flags = 0; flags = 0;
@ -885,7 +882,7 @@ converter_generic (GstAudioConverter * convert,
/** /**
* gst_audio_converter_new: (skip) * gst_audio_converter_new: (skip)
* @flags: #GstAudioConverterFlags * @flags: extra #GstAudioConverterFlags
* @in_info: a source #GstAudioInfo * @in_info: a source #GstAudioInfo
* @out_info: a destination #GstAudioInfo * @out_info: a destination #GstAudioInfo
* @config: (transfer full): a #GstStructure with configuration options * @config: (transfer full): a #GstStructure with configuration options
@ -1062,52 +1059,6 @@ gst_audio_converter_get_max_latency (GstAudioConverter * convert)
return 0; return 0;
} }
/**
* gst_audio_converter_update_rates:
* @convert: a #GstAudioConverter
* @in_rate: input rate
* @out_rate: output rate
* @options: resampler options
*
* Update the input and output rates, passing @options to the resampler.
*
* Returns: %TRUE on success.
*/
gboolean
gst_audio_converter_update_rates (GstAudioConverter * convert,
gint in_rate, gint out_rate, GstStructure * options)
{
g_return_val_if_fail (convert != NULL, FALSE);
g_return_val_if_fail (in_rate > 0, FALSE);
g_return_val_if_fail (out_rate > 0, FALSE);
convert->in.rate = in_rate;
convert->out.rate = out_rate;
if (options)
gst_structure_free (options);
return TRUE;
}
/**
* gst_audio_converter_get_rates:
* @convert: a #GstAudioConverter
* @in_rate: input rate
* @out_rate: output rate
*
* Get the current input and output rates.
*/
void
gst_audio_converter_get_rates (GstAudioConverter * convert,
gint * in_rate, gint * out_rate)
{
if (in_rate)
*in_rate = convert->in.rate;
if (out_rate)
*out_rate = convert->out.rate;
}
/** /**
* gst_audio_converter_reset: * gst_audio_converter_reset:
* @convert: a #GstAudioConverter * @convert: a #GstAudioConverter
@ -1158,8 +1109,6 @@ gst_audio_converter_samples (GstAudioConverter * convert,
g_return_val_if_fail (convert != NULL, FALSE); g_return_val_if_fail (convert != NULL, FALSE);
g_return_val_if_fail (out != NULL, FALSE); g_return_val_if_fail (out != NULL, FALSE);
in_frames = MIN (in_frames, out_frames);
if (in_frames == 0) { if (in_frames == 0) {
GST_LOG ("skipping empty buffer"); GST_LOG ("skipping empty buffer");
return TRUE; return TRUE;

View file

@ -103,12 +103,6 @@ gsize gst_audio_converter_get_in_frames (GstAudioConverter *con
gsize gst_audio_converter_get_max_latency (GstAudioConverter *convert); gsize gst_audio_converter_get_max_latency (GstAudioConverter *convert);
gboolean gst_audio_converter_update_rates (GstAudioConverter *convert,
gint in_rate, gint out_rate,
GstStructure *options);
void gst_audio_converter_get_rates (GstAudioConverter *convert,
gint *in_rate, gint *out_rate);
gboolean gst_audio_converter_samples (GstAudioConverter * convert, gboolean gst_audio_converter_samples (GstAudioConverter * convert,
GstAudioConverterFlags flags, GstAudioConverterFlags flags,
gpointer in[], gsize in_frames, gpointer in[], gsize in_frames,

View file

@ -39,7 +39,7 @@ typedef struct _Tap
typedef void (*MakeTapsFunc) (GstAudioResampler * resampler, Tap * t, gint j); typedef void (*MakeTapsFunc) (GstAudioResampler * resampler, Tap * t, gint j);
typedef void (*ResampleFunc) (GstAudioResampler * resampler, gpointer in[], typedef void (*ResampleFunc) (GstAudioResampler * resampler, gpointer in[],
gsize in_len, gpointer out[], gsize out_len, gsize * consumed, gsize in_len, gpointer out[], gsize out_len, gsize * consumed,
gsize * produced, gboolean move); gboolean move);
typedef void (*DeinterleaveFunc) (GstAudioResampler * resampler, typedef void (*DeinterleaveFunc) (GstAudioResampler * resampler,
gpointer * sbuf, gpointer in[], gsize in_frames); gpointer * sbuf, gpointer in[], gsize in_frames);
typedef void (*MirrorFunc) (GstAudioResampler * resampler, gpointer * sbuf); typedef void (*MirrorFunc) (GstAudioResampler * resampler, gpointer * sbuf);
@ -377,8 +377,7 @@ make_taps (GstAudioResampler * resampler, Tap * t, gint j)
#define MAKE_RESAMPLE_FUNC(type) \ #define MAKE_RESAMPLE_FUNC(type) \
static void \ static void \
resample_ ##type (GstAudioResampler * resampler, gpointer in[], gsize in_len, \ resample_ ##type (GstAudioResampler * resampler, gpointer in[], gsize in_len, \
gpointer out[], gsize out_len, gsize * consumed, gsize * produced, \ gpointer out[], gsize out_len, gsize * consumed, gboolean move) \
gboolean move) \
{ \ { \
gint c, di = 0; \ gint c, di = 0; \
gint n_taps = resampler->n_taps; \ gint n_taps = resampler->n_taps; \
@ -411,7 +410,6 @@ resample_ ##type (GstAudioResampler * resampler, gpointer in[], gsize in_len,
memmove (ip, &ip[samp_index], (in_len - samp_index) * sizeof(type)); \ memmove (ip, &ip[samp_index], (in_len - samp_index) * sizeof(type)); \
} \ } \
*consumed = samp_index - resampler->samp_index; \ *consumed = samp_index - resampler->samp_index; \
*produced = di; \
\ \
resampler->samp_index = move ? 0 : samp_index; \ resampler->samp_index = move ? 0 : samp_index; \
resampler->samp_phase = samp_phase; \ resampler->samp_phase = samp_phase; \
@ -425,8 +423,7 @@ MAKE_RESAMPLE_FUNC (gint16);
#define MAKE_RESAMPLE_INTERLEAVED_FUNC(type,channels) \ #define MAKE_RESAMPLE_INTERLEAVED_FUNC(type,channels) \
static void \ static void \
resample_interleaved_ ##type##_##channels (GstAudioResampler * resampler, gpointer in[],\ resample_interleaved_ ##type##_##channels (GstAudioResampler * resampler, gpointer in[],\
gsize in_len, gpointer out[], gsize out_len, gsize * consumed, gsize * produced, \ gsize in_len, gpointer out[], gsize out_len, gsize * consumed, gboolean move) \
gboolean move) \
{ \ { \
gint di = 0; \ gint di = 0; \
gint n_taps = resampler->n_taps; \ gint n_taps = resampler->n_taps; \
@ -459,7 +456,6 @@ resample_interleaved_ ##type##_##channels (GstAudioResampler * resampler, gpoint
(in_len - samp_index) * sizeof(type) * channels); \ (in_len - samp_index) * sizeof(type) * channels); \
} \ } \
*consumed = samp_index - resampler->samp_index; \ *consumed = samp_index - resampler->samp_index; \
*produced = di; \
\ \
resampler->samp_index = move ? 0 : samp_index; \ resampler->samp_index = move ? 0 : samp_index; \
resampler->samp_phase = samp_phase; \ resampler->samp_phase = samp_phase; \
@ -861,6 +857,8 @@ gst_audio_resampler_new (GstAudioResamplerMethod method,
* Update the resampler parameters for @resampler. This function should * Update the resampler parameters for @resampler. This function should
* not be called concurrently with any other function on @resampler. * not be called concurrently with any other function on @resampler.
* *
* When @in_rate or @out_rate is 0, its value is unchanged.
*
* Returns: %TRUE if the new parameters could be set * Returns: %TRUE if the new parameters could be set
*/ */
gboolean gboolean
@ -870,8 +868,11 @@ gst_audio_resampler_update (GstAudioResampler * resampler,
gint gcd; gint gcd;
g_return_val_if_fail (resampler != NULL, FALSE); g_return_val_if_fail (resampler != NULL, FALSE);
g_return_val_if_fail (in_rate != 0, FALSE);
g_return_val_if_fail (out_rate != 0, FALSE); if (in_rate == 0)
in_rate = resampler->in_rate;
if (out_rate == 0)
out_rate = resampler->out_rate;
gcd = gst_util_greatest_common_divisor (in_rate, out_rate); gcd = gst_util_greatest_common_divisor (in_rate, out_rate);
in_rate /= gcd; in_rate /= gcd;
@ -1034,12 +1035,9 @@ get_sample_bufs (GstAudioResampler * resampler, gsize need)
* @in: input samples * @in: input samples
* @in_frames: number of input frames * @in_frames: number of input frames
* @out: output samples * @out: output samples
* @out_frames: maximum output frames * @out_frames: number of output frames
* @in_consumed: number of frames consumed
* @out_produced: number of frames produced
* *
* Perform resampling on @in_frames frames in @in and write at most * Perform resampling on @in_frames frames in @in and write @out_frames to @out.
* @out_frames of frames to @out.
* *
* In case the samples are interleaved, @in and @out must point to an * 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. * array with a single element pointing to a block of interleaved samples.
@ -1047,30 +1045,26 @@ get_sample_bufs (GstAudioResampler * resampler, gsize need)
* If non-interleaved samples are used, @in and @out must point to an * If non-interleaved samples are used, @in and @out must point to an
* array with pointers to memory blocks, one for each channel. * array with pointers to memory blocks, one for each channel.
* *
* @in may be %NULL, in which case @in_frames of 0 samples are pushed * @in may be %NULL, in which case @in_frames of silence samples are pushed
* into the resampler. * into the resampler.
* *
* The number of frames consumed is returned in @consumed and can be * This function always produces @out_frames of output and consumes @in_frames of
* less than @in_frames due to latency of the resampler or because * input. Use gst_audio_resampler_get_out_frames() and
* the number of samples produced equals @out_frames. * gst_audio_resampler_get_in_frames() to make sure @in_frames and @out_frames
* * are matching and @in and @out point to enough memory.
* The number of frames produced is returned in @produced.
*/ */
void void
gst_audio_resampler_resample (GstAudioResampler * resampler, gst_audio_resampler_resample (GstAudioResampler * resampler,
gpointer in[], gsize in_frames, gpointer out[], gsize out_frames, gpointer in[], gsize in_frames, gpointer out[], gsize out_frames)
gsize * in_consumed, gsize * out_produced)
{ {
gsize samples_avail; gsize samples_avail;
gsize out2, need; gsize need, consumed;
gpointer *sbuf; gpointer *sbuf;
/* do sample skipping */ /* do sample skipping */
if (resampler->skip >= in_frames) { if (resampler->skip >= in_frames) {
/* we need tp skip all input */ /* we need tp skip all input */
resampler->skip -= in_frames; resampler->skip -= in_frames;
*in_consumed = in_frames;
*out_produced = 0;
return; return;
} }
/* skip the last samples by advancing the sample index */ /* skip the last samples by advancing the sample index */
@ -1090,8 +1084,6 @@ gst_audio_resampler_resample (GstAudioResampler * resampler,
need = resampler->n_taps + resampler->samp_index; need = resampler->n_taps + resampler->samp_index;
if (samples_avail < need) { if (samples_avail < need) {
/* not enough samples to start */ /* not enough samples to start */
*in_consumed = in_frames;
*out_produced = 0;
return; return;
} }
@ -1101,21 +1093,16 @@ gst_audio_resampler_resample (GstAudioResampler * resampler,
resampler->filling = FALSE; resampler->filling = FALSE;
} }
/* calculate maximum number of available output samples */
out2 = calc_out (resampler, samples_avail - need);
out_frames = MIN (out2, out_frames);
/* resample all channels */ /* resample all channels */
resampler->resample (resampler, sbuf, samples_avail, out, out_frames, resampler->resample (resampler, sbuf, samples_avail, out, out_frames,
in_consumed, out_produced, TRUE); &consumed, TRUE);
GST_LOG ("in %" G_GSIZE_FORMAT ", used %" G_GSIZE_FORMAT ", consumed %" GST_LOG ("in %" G_GSIZE_FORMAT ", used %" G_GSIZE_FORMAT ", consumed %"
G_GSIZE_FORMAT ", produced %" G_GSIZE_FORMAT, in_frames, samples_avail, G_GSIZE_FORMAT, in_frames, samples_avail, consumed);
*in_consumed, *out_produced);
/* update pointers */ /* update pointers */
if (*in_consumed > 0) { if (consumed > 0) {
gssize left = samples_avail - *in_consumed; gssize left = samples_avail - consumed;
if (left > 0) { if (left > 0) {
/* we consumed part of our samples */ /* we consumed part of our samples */
resampler->samples_avail = left; resampler->samples_avail = left;
@ -1124,7 +1111,5 @@ gst_audio_resampler_resample (GstAudioResampler * resampler,
resampler->samples_avail = 0; resampler->samples_avail = 0;
resampler->skip = -left; resampler->skip = -left;
} }
/* we always consume everything */
*in_consumed = in_frames;
} }
} }

View file

@ -178,8 +178,7 @@ gsize gst_audio_resampler_get_max_latency (GstAudioResampler *res
void gst_audio_resampler_resample (GstAudioResampler * resampler, void gst_audio_resampler_resample (GstAudioResampler * resampler,
gpointer in[], gsize in_frames, gpointer in[], gsize in_frames,
gpointer out[], gsize out_frames, gpointer out[], gsize out_frames);
gsize *in_consumed, gsize *out_produced);
G_END_DECLS G_END_DECLS

View file

@ -386,14 +386,16 @@ gst_audio_resample_update_state (GstAudioResample * resample, GstAudioInfo * in,
resample->converter = NULL; resample->converter = NULL;
} }
if (resample->converter == NULL) { if (resample->converter == NULL) {
resample->converter = gst_audio_converter_new (0, in, out, options); resample->converter =
gst_audio_converter_new (GST_AUDIO_CONVERTER_FLAG_VARIABLE_RATE, in,
out, options);
if (resample->converter == NULL) if (resample->converter == NULL)
goto resampler_failed; goto resampler_failed;
} else if (in && out) { } else if (in && out) {
gboolean ret; gboolean ret;
ret = ret =
gst_audio_converter_update_rates (resample->converter, in->rate, gst_audio_converter_update_config (resample->converter, in->rate,
out->rate, options); out->rate, options);
if (!ret) if (!ret)
goto update_failed; goto update_failed;
@ -568,8 +570,7 @@ gst_audio_resample_push_drain (GstAudioResample * resample, guint history_len)
GstBuffer *outbuf; GstBuffer *outbuf;
GstFlowReturn res; GstFlowReturn res;
gint outsize; gint outsize;
gsize in_processed; gsize out_len;
gsize out_len, out_processed;
GstMapInfo map; GstMapInfo map;
gpointer out[1]; gpointer out[1];
@ -591,11 +592,8 @@ gst_audio_resample_push_drain (GstAudioResample * resample, guint history_len)
out[0] = map.data; out[0] = map.data;
gst_audio_converter_samples (resample->converter, 0, NULL, history_len, gst_audio_converter_samples (resample->converter, 0, NULL, history_len,
out, out_len, &in_processed, &out_processed); out, out_len);
/* If we wrote more than allocated something is really wrong now
* and we should better abort immediately */
g_assert (out_len == out_processed);
gst_buffer_unmap (outbuf, &map); gst_buffer_unmap (outbuf, &map);
/* time */ /* time */
@ -604,7 +602,7 @@ gst_audio_resample_push_drain (GstAudioResample * resample, guint history_len)
gst_util_uint64_scale_int_round (resample->samples_out, GST_SECOND, gst_util_uint64_scale_int_round (resample->samples_out, GST_SECOND,
resample->out.rate); resample->out.rate);
GST_BUFFER_DURATION (outbuf) = resample->t0 + GST_BUFFER_DURATION (outbuf) = resample->t0 +
gst_util_uint64_scale_int_round (resample->samples_out + out_processed, gst_util_uint64_scale_int_round (resample->samples_out + out_len,
GST_SECOND, resample->out.rate) - GST_BUFFER_TIMESTAMP (outbuf); GST_SECOND, resample->out.rate) - GST_BUFFER_TIMESTAMP (outbuf);
} else { } else {
GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE; GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
@ -613,13 +611,13 @@ gst_audio_resample_push_drain (GstAudioResample * resample, guint history_len)
/* offset */ /* offset */
if (resample->out_offset0 != GST_BUFFER_OFFSET_NONE) { if (resample->out_offset0 != GST_BUFFER_OFFSET_NONE) {
GST_BUFFER_OFFSET (outbuf) = resample->out_offset0 + resample->samples_out; GST_BUFFER_OFFSET (outbuf) = resample->out_offset0 + resample->samples_out;
GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET (outbuf) + out_processed; GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET (outbuf) + out_len;
} else { } else {
GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET_NONE; GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET_NONE;
GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_NONE; GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_NONE;
} }
/* move along */ /* move along */
resample->samples_out += out_processed; resample->samples_out += out_len;
resample->samples_in += history_len; resample->samples_in += history_len;
GST_LOG_OBJECT (resample, GST_LOG_OBJECT (resample,
@ -742,20 +740,23 @@ gst_audio_resample_process (GstAudioResample * resample, GstBuffer * inbuf,
{ {
GstMapInfo in_map, out_map; GstMapInfo in_map, out_map;
gsize outsize; gsize outsize;
guint32 in_len, in_processed; guint32 in_len;
guint32 out_len, out_processed; guint32 out_len;
guint filt_len = guint filt_len =
gst_audio_converter_get_max_latency (resample->converter) * 2; gst_audio_converter_get_max_latency (resample->converter) * 2;
gboolean inbuf_writable;
gst_buffer_map (inbuf, &in_map, GST_MAP_READ); inbuf_writable = gst_buffer_is_writable (inbuf)
&& gst_buffer_n_memory (inbuf) == 1
&& gst_memory_is_writable (gst_buffer_peek_memory (inbuf, 0));
gst_buffer_map (inbuf, &in_map,
inbuf_writable ? GST_MAP_READWRITE : GST_MAP_READ);
gst_buffer_map (outbuf, &out_map, GST_MAP_WRITE); gst_buffer_map (outbuf, &out_map, GST_MAP_WRITE);
in_len = in_map.size / resample->in.bpf; in_len = in_map.size / resample->in.bpf;
out_len = out_map.size / resample->out.bpf; out_len = out_map.size / resample->out.bpf;
in_processed = in_len;
out_processed = out_len;
if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) { if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) {
resample->num_nongap_samples = 0; resample->num_nongap_samples = 0;
if (resample->num_gap_samples < filt_len) { if (resample->num_gap_samples < filt_len) {
@ -777,16 +778,15 @@ gst_audio_resample_process (GstAudioResample * resample, GstBuffer * inbuf,
den = resample->out.rate; den = resample->out.rate;
if (resample->samples_in + in_len >= filt_len / 2) if (resample->samples_in + in_len >= filt_len / 2)
out_processed = out_len =
gst_util_uint64_scale_int_ceil (resample->samples_in + in_len - gst_util_uint64_scale_int_ceil (resample->samples_in + in_len -
filt_len / 2, den, num) - resample->samples_out; filt_len / 2, den, num) - resample->samples_out;
else else
out_processed = 0; out_len = 0;
memset (out_map.data, 0, out_map.size); memset (out_map.data, 0, out_map.size);
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP); GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
resample->num_gap_samples += in_len; resample->num_gap_samples += in_len;
in_processed = in_len;
} }
} else { /* not a gap */ } else { /* not a gap */
if (resample->num_gap_samples > filt_len) { if (resample->num_gap_samples > filt_len) {
@ -807,43 +807,31 @@ gst_audio_resample_process (GstAudioResample * resample, GstBuffer * inbuf,
{ {
/* process */ /* process */
{ {
gsize in_proc, out_proc, out_test;
gpointer in[1], out[1]; gpointer in[1], out[1];
GstAudioConverterFlags flags;
out_test = out_len =
gst_audio_converter_get_out_frames (resample->converter, in_len); gst_audio_converter_get_out_frames (resample->converter, in_len);
out_test = MIN (out_test, out_len);
flags = 0;
if (inbuf_writable)
flags |= GST_AUDIO_CONVERTER_FLAG_IN_WRITABLE;
in[0] = in_map.data; in[0] = in_map.data;
out[0] = out_map.data; out[0] = out_map.data;
gst_audio_converter_samples (resample->converter, 0, in, in_len, gst_audio_converter_samples (resample->converter, flags, in, in_len,
out, out_len, &in_proc, &out_proc); out, out_len);
in_processed = in_proc;
out_processed = out_proc;
//g_printerr ("in %d, test %d, %d, real %d (%d)\n", (gint) in_len, (gint) out_test, (gint) out_len, (gint) out_proc, (gint) (out_test - out_proc));
g_assert (out_test == out_proc);
} }
} }
} }
/* If we wrote more than allocated something is really wrong now and we
* should better abort immediately */
g_assert (out_len >= out_processed);
if (G_UNLIKELY (in_len != in_processed)) {
GST_WARNING_OBJECT (resample, "converted %d of %d input samples",
in_processed, in_len);
}
/* time */ /* time */
if (GST_CLOCK_TIME_IS_VALID (resample->t0)) { if (GST_CLOCK_TIME_IS_VALID (resample->t0)) {
GST_BUFFER_TIMESTAMP (outbuf) = resample->t0 + GST_BUFFER_TIMESTAMP (outbuf) = resample->t0 +
gst_util_uint64_scale_int_round (resample->samples_out, GST_SECOND, gst_util_uint64_scale_int_round (resample->samples_out, GST_SECOND,
resample->out.rate); resample->out.rate);
GST_BUFFER_DURATION (outbuf) = resample->t0 + GST_BUFFER_DURATION (outbuf) = resample->t0 +
gst_util_uint64_scale_int_round (resample->samples_out + out_processed, gst_util_uint64_scale_int_round (resample->samples_out + out_len,
GST_SECOND, resample->out.rate) - GST_BUFFER_TIMESTAMP (outbuf); GST_SECOND, resample->out.rate) - GST_BUFFER_TIMESTAMP (outbuf);
} else { } else {
GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE; GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
@ -852,26 +840,26 @@ gst_audio_resample_process (GstAudioResample * resample, GstBuffer * inbuf,
/* offset */ /* offset */
if (resample->out_offset0 != GST_BUFFER_OFFSET_NONE) { if (resample->out_offset0 != GST_BUFFER_OFFSET_NONE) {
GST_BUFFER_OFFSET (outbuf) = resample->out_offset0 + resample->samples_out; GST_BUFFER_OFFSET (outbuf) = resample->out_offset0 + resample->samples_out;
GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET (outbuf) + out_processed; GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET (outbuf) + out_len;
} else { } else {
GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET_NONE; GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET_NONE;
GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_NONE; GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_NONE;
} }
/* move along */ /* move along */
resample->samples_out += out_processed; resample->samples_out += out_len;
resample->samples_in += in_len; resample->samples_in += in_len;
gst_buffer_unmap (inbuf, &in_map); gst_buffer_unmap (inbuf, &in_map);
gst_buffer_unmap (outbuf, &out_map); gst_buffer_unmap (outbuf, &out_map);
outsize = out_processed * resample->in.bpf; outsize = out_len * resample->in.bpf;
gst_buffer_resize (outbuf, 0, outsize); gst_buffer_resize (outbuf, 0, outsize);
GST_LOG_OBJECT (resample, GST_LOG_OBJECT (resample,
"Converted to buffer of %" G_GUINT32_FORMAT "Converted to buffer of %" G_GUINT32_FORMAT
" samples (%" G_GSIZE_FORMAT " bytes) with timestamp %" GST_TIME_FORMAT " samples (%" G_GSIZE_FORMAT " bytes) with timestamp %" GST_TIME_FORMAT
", duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT ", duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
", offset_end %" G_GUINT64_FORMAT, out_processed, outsize, ", offset_end %" G_GUINT64_FORMAT, out_len, outsize,
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
GST_BUFFER_OFFSET (outbuf), GST_BUFFER_OFFSET_END (outbuf)); GST_BUFFER_OFFSET (outbuf), GST_BUFFER_OFFSET_END (outbuf));