}
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
audio_chain_set_samples (AudioChain * chain, gpointer * samples,
gsize num_samples)
{
- if (num_samples == 0)
- return;
-
- GST_LOG ("set samples %" G_GSIZE_FORMAT, num_samples);
+ GST_LOG ("set samples %p %" G_GSIZE_FORMAT, samples, num_samples);
chain->samples = samples;
chain->num_samples = num_samples;
*
* 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.
*
* @config can be %NULL, in which case, the current configuration is not
gst_structure_free (config);
}
+ if (convert->resampler)
+ gst_audio_resampler_update (convert->resampler, in_rate, out_rate,
+ convert->config);
+
return TRUE;
}
}
} else {
tmp = convert->in_data;
- num_samples = convert->in_samples;
GST_LOG ("get in samples %p", tmp);
}
audio_chain_set_samples (chain, tmp, num_samples);
static gboolean
do_convert_in (AudioChain * chain, gpointer user_data)
{
- GstAudioConverter *convert = user_data;
gsize num_samples;
+ GstAudioConverter *convert = user_data;
gpointer *in, *out;
gint i;
static gboolean
do_mix (AudioChain * chain, gpointer user_data)
{
- GstAudioConverter *convert = user_data;
gsize num_samples;
+ GstAudioConverter *convert = user_data;
gpointer *in, *out;
in = audio_chain_get_samples (chain->prev, &num_samples);
{
GstAudioConverter *convert = user_data;
gpointer *in, *out;
- gsize in_frames, out_frames, produced, consumed;
+ gsize in_frames, out_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_audio_resampler_get_out_frames (convert->resampler, in_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_LOG ("resample %p %p,%" G_GSIZE_FORMAT " %" G_GSIZE_FORMAT, in,
+ out, in_frames, out_frames);
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;
}
in = audio_chain_get_samples (chain->prev, &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++)
convert->convert_out (out[i], in[i], num_samples * chain->inc);
in = audio_chain_get_samples (chain->prev, &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);
GstAudioFormat format = convert->current_format;
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);
flags = 0;
/**
* gst_audio_converter_new: (skip)
- * @flags: #GstAudioConverterFlags
+ * @flags: extra #GstAudioConverterFlags
* @in_info: a source #GstAudioInfo
* @out_info: a destination #GstAudioInfo
* @config: (transfer full): a #GstStructure with configuration options
}
/**
- * 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:
* @convert: a #GstAudioConverter
*
g_return_val_if_fail (convert != NULL, FALSE);
g_return_val_if_fail (out != NULL, FALSE);
- in_frames = MIN (in_frames, out_frames);
-
if (in_frames == 0) {
GST_LOG ("skipping empty buffer");
return TRUE;
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,
GstAudioConverterFlags flags,
gpointer in[], gsize in_frames,
typedef void (*MakeTapsFunc) (GstAudioResampler * resampler, Tap * t, gint j);
typedef void (*ResampleFunc) (GstAudioResampler * resampler, gpointer in[],
gsize in_len, gpointer out[], gsize out_len, gsize * consumed,
- gsize * produced, gboolean move);
+ gboolean move);
typedef void (*DeinterleaveFunc) (GstAudioResampler * resampler,
gpointer * sbuf, gpointer in[], gsize in_frames);
typedef void (*MirrorFunc) (GstAudioResampler * resampler, gpointer * sbuf);
#define MAKE_RESAMPLE_FUNC(type) \
static void \
resample_ ##type (GstAudioResampler * resampler, gpointer in[], gsize in_len, \
- gpointer out[], gsize out_len, gsize * consumed, gsize * produced, \
- gboolean move) \
+ gpointer out[], gsize out_len, gsize * consumed, gboolean move) \
{ \
gint c, di = 0; \
gint n_taps = resampler->n_taps; \
memmove (ip, &ip[samp_index], (in_len - samp_index) * sizeof(type)); \
} \
*consumed = samp_index - resampler->samp_index; \
- *produced = di; \
\
resampler->samp_index = move ? 0 : samp_index; \
resampler->samp_phase = samp_phase; \
#define MAKE_RESAMPLE_INTERLEAVED_FUNC(type,channels) \
static void \
resample_interleaved_ ##type##_##channels (GstAudioResampler * resampler, gpointer in[],\
- gsize in_len, gpointer out[], gsize out_len, gsize * consumed, gsize * produced, \
- gboolean move) \
+ gsize in_len, gpointer out[], gsize out_len, gsize * consumed, gboolean move) \
{ \
gint di = 0; \
gint n_taps = resampler->n_taps; \
(in_len - samp_index) * sizeof(type) * channels); \
} \
*consumed = samp_index - resampler->samp_index; \
- *produced = di; \
\
resampler->samp_index = move ? 0 : samp_index; \
resampler->samp_phase = samp_phase; \
* Update the resampler parameters for @resampler. This function should
* 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
*/
gboolean
gint gcd;
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);
in_rate /= gcd;
* @in: input samples
* @in_frames: number of input frames
* @out: output samples
- * @out_frames: maximum output frames
- * @in_consumed: number of frames consumed
- * @out_produced: number of frames produced
+ * @out_frames: number of output frames
*
- * Perform resampling on @in_frames frames in @in and write at most
- * @out_frames of frames to @out.
+ * Perform resampling on @in_frames frames in @in and write @out_frames to @out.
*
* 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 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.
*
- * The number of frames consumed is returned in @consumed and can be
- * less than @in_frames due to latency of the resampler or because
- * the number of samples produced equals @out_frames.
- *
- * The number of frames produced is returned in @produced.
+ * This function always produces @out_frames of output and consumes @in_frames of
+ * input. Use gst_audio_resampler_get_out_frames() and
+ * gst_audio_resampler_get_in_frames() to make sure @in_frames and @out_frames
+ * are matching and @in and @out point to enough memory.
*/
void
gst_audio_resampler_resample (GstAudioResampler * resampler,
- gpointer in[], gsize in_frames, gpointer out[], gsize out_frames,
- gsize * in_consumed, gsize * out_produced)
+ gpointer in[], gsize in_frames, gpointer out[], gsize out_frames)
{
gsize samples_avail;
- gsize out2, need;
+ gsize need, consumed;
gpointer *sbuf;
/* do sample skipping */
if (resampler->skip >= in_frames) {
/* we need tp skip all input */
resampler->skip -= in_frames;
- *in_consumed = in_frames;
- *out_produced = 0;
return;
}
/* skip the last samples by advancing the sample index */
need = resampler->n_taps + resampler->samp_index;
if (samples_avail < need) {
/* not enough samples to start */
- *in_consumed = in_frames;
- *out_produced = 0;
return;
}
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 */
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 %"
- G_GSIZE_FORMAT ", produced %" G_GSIZE_FORMAT, in_frames, samples_avail,
- *in_consumed, *out_produced);
+ G_GSIZE_FORMAT, in_frames, samples_avail, consumed);
/* update pointers */
- if (*in_consumed > 0) {
- gssize left = samples_avail - *in_consumed;
+ if (consumed > 0) {
+ gssize left = samples_avail - consumed;
if (left > 0) {
/* we consumed part of our samples */
resampler->samples_avail = left;
resampler->samples_avail = 0;
resampler->skip = -left;
}
- /* we always consume everything */
- *in_consumed = in_frames;
}
}
void gst_audio_resampler_resample (GstAudioResampler * resampler,
gpointer in[], gsize in_frames,
- gpointer out[], gsize out_frames,
- gsize *in_consumed, gsize *out_produced);
+ gpointer out[], gsize out_frames);
G_END_DECLS
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)
goto resampler_failed;
} else if (in && out) {
gboolean ret;
ret =
- gst_audio_converter_update_rates (resample->converter, in->rate,
+ gst_audio_converter_update_config (resample->converter, in->rate,
out->rate, options);
if (!ret)
goto update_failed;
GstBuffer *outbuf;
GstFlowReturn res;
gint outsize;
- gsize in_processed;
- gsize out_len, out_processed;
+ gsize out_len;
GstMapInfo map;
gpointer out[1];
out[0] = map.data;
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);
/* time */
gst_util_uint64_scale_int_round (resample->samples_out, GST_SECOND,
resample->out.rate);
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);
} else {
GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
/* offset */
if (resample->out_offset0 != GST_BUFFER_OFFSET_NONE) {
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 {
GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET_NONE;
GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_NONE;
}
/* move along */
- resample->samples_out += out_processed;
+ resample->samples_out += out_len;
resample->samples_in += history_len;
GST_LOG_OBJECT (resample,
{
GstMapInfo in_map, out_map;
gsize outsize;
- guint32 in_len, in_processed;
- guint32 out_len, out_processed;
+ guint32 in_len;
+ guint32 out_len;
guint filt_len =
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);
in_len = in_map.size / resample->in.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)) {
resample->num_nongap_samples = 0;
if (resample->num_gap_samples < filt_len) {
den = resample->out.rate;
if (resample->samples_in + in_len >= filt_len / 2)
- out_processed =
+ out_len =
gst_util_uint64_scale_int_ceil (resample->samples_in + in_len -
filt_len / 2, den, num) - resample->samples_out;
else
- out_processed = 0;
+ out_len = 0;
memset (out_map.data, 0, out_map.size);
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
resample->num_gap_samples += in_len;
- in_processed = in_len;
}
} else { /* not a gap */
if (resample->num_gap_samples > filt_len) {
{
/* process */
{
- gsize in_proc, out_proc, out_test;
gpointer in[1], out[1];
+ GstAudioConverterFlags flags;
- out_test =
+ out_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;
out[0] = out_map.data;
- gst_audio_converter_samples (resample->converter, 0, in, in_len,
- out, out_len, &in_proc, &out_proc);
-
- 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);
+ gst_audio_converter_samples (resample->converter, flags, in, in_len,
+ 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);
-
- if (G_UNLIKELY (in_len != in_processed)) {
- GST_WARNING_OBJECT (resample, "converted %d of %d input samples",
- in_processed, in_len);
- }
-
/* time */
if (GST_CLOCK_TIME_IS_VALID (resample->t0)) {
GST_BUFFER_TIMESTAMP (outbuf) = resample->t0 +
gst_util_uint64_scale_int_round (resample->samples_out, GST_SECOND,
resample->out.rate);
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);
} else {
GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
/* offset */
if (resample->out_offset0 != GST_BUFFER_OFFSET_NONE) {
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 {
GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET_NONE;
GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_NONE;
}
/* move along */
- resample->samples_out += out_processed;
+ resample->samples_out += out_len;
resample->samples_in += in_len;
gst_buffer_unmap (inbuf, &in_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_LOG_OBJECT (resample,
"Converted to buffer of %" G_GUINT32_FORMAT
" samples (%" G_GSIZE_FORMAT " bytes) with timestamp %" GST_TIME_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_DURATION (outbuf)),
GST_BUFFER_OFFSET (outbuf), GST_BUFFER_OFFSET_END (outbuf));