summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Singer <leo.singer@ligo.org>2010-12-16 20:09:58 -0800
committerSebastian Dröge <sebastian.droege@collabora.co.uk>2010-12-17 19:34:41 +0100
commitb4cd3329a96b934c227b76c6dec955190a4dc3d8 (patch)
treed97f901fe778203dd4a578fd7c80b058ff7b30db
parent270bac8158be27d843d00c94dd7873723417e069 (diff)
Revert "Revert "audioresample: Add GAP flag support""
This reverts commit 35c76b3409dde7f2dcc8232388a47a1b99b661a7. Conflicts: gst/audioresample/gstaudioresample.c gst/audioresample/gstaudioresample.h
-rw-r--r--gst/audioresample/gstaudioresample.c202
-rw-r--r--gst/audioresample/gstaudioresample.h3
-rw-r--r--gst/audioresample/resample.c6
-rw-r--r--gst/audioresample/speex_resampler.h6
-rw-r--r--gst/audioresample/speex_resampler_wrapper.h7
5 files changed, 172 insertions, 52 deletions
diff --git a/gst/audioresample/gstaudioresample.c b/gst/audioresample/gstaudioresample.c
index 42597e45c..a1da42f34 100644
--- a/gst/audioresample/gstaudioresample.c
+++ b/gst/audioresample/gstaudioresample.c
@@ -224,6 +224,7 @@ gst_audio_resample_init (GstAudioResample * resample,
resample->quality = SPEEX_RESAMPLER_QUALITY_DEFAULT;
+ gst_base_transform_set_gap_aware (trans, TRUE);
gst_pad_set_query_function (trans->srcpad, gst_audio_resample_query);
gst_pad_set_query_type_function (trans->srcpad,
gst_audio_resample_query_type);
@@ -237,6 +238,8 @@ gst_audio_resample_start (GstBaseTransform * base)
resample->need_discont = TRUE;
+ resample->count_gap = 0;
+ resample->count_nongap = 0;
resample->t0 = GST_CLOCK_TIME_NONE;
resample->in_offset0 = GST_BUFFER_OFFSET_NONE;
resample->out_offset0 = GST_BUFFER_OFFSET_NONE;
@@ -386,8 +389,6 @@ gst_audio_resample_init_state (GstAudioResample * resample, gint width,
return NULL;
}
- funcs->skip_zeros (ret);
-
return ret;
}
@@ -781,18 +782,48 @@ gst_audio_resample_workspace_realloc (guint8 ** workspace, guint * size,
return *workspace;
}
+/* Push history_len zeros into the filter, but discard the output. */
static void
-gst_audio_resample_push_drain (GstAudioResample * resample)
+gst_audio_resample_dump_drain (GstAudioResample * resample, guint history_len)
+{
+ gint outsize;
+ guint in_len, in_processed;
+ guint out_len, out_processed;
+ guint num, den;
+ void *buf;
+
+ g_assert (resample->state != NULL);
+
+ resample->funcs->get_ratio (resample->state, &num, &den);
+
+ in_len = in_processed = history_len;
+ out_processed = out_len =
+ gst_util_uint64_scale_int_ceil (history_len, den, num);
+ outsize = out_len * resample->channels * (resample->funcs->width / 8);
+
+ if (out_len == 0)
+ return;
+
+ buf = g_malloc (outsize);
+ resample->funcs->process (resample->state, NULL, &in_processed, buf,
+ &out_processed);
+ g_free (buf);
+
+ g_assert (in_len == in_processed);
+}
+
+static void
+gst_audio_resample_push_drain (GstAudioResample * resample, guint history_len)
{
GstBuffer *outbuf;
GstFlowReturn res;
gint outsize;
- guint history_len, out_len, out_processed;
+ guint in_len, in_processed;
+ guint out_len, out_processed;
gint err;
guint num, den;
- if (!resample->state)
- return;
+ g_assert (resample->state != NULL);
/* Don't drain samples if we were reset. */
if (!GST_CLOCK_TIME_IS_VALID (resample->t0))
@@ -800,11 +831,14 @@ gst_audio_resample_push_drain (GstAudioResample * resample)
resample->funcs->get_ratio (resample->state, &num, &den);
- history_len = resample->funcs->get_input_latency (resample->state);
+ in_len = in_processed = history_len;
out_len = out_processed =
gst_util_uint64_scale_int_ceil (history_len, den, num);
outsize = out_len * resample->channels * (resample->width / 8);
+ if (out_len == 0)
+ return;
+
res =
gst_pad_alloc_buffer_and_set_caps (GST_BASE_TRANSFORM_SRC_PAD (resample),
GST_BUFFER_OFFSET_NONE, outsize,
@@ -825,7 +859,7 @@ gst_audio_resample_push_drain (GstAudioResample * resample)
}
/* process */
- err = resample->funcs->process (resample->state, NULL, &history_len,
+ err = resample->funcs->process (resample->state, NULL, &in_processed,
resample->tmp_out, &out_processed);
/* convert output format */
@@ -833,7 +867,7 @@ gst_audio_resample_push_drain (GstAudioResample * resample)
GST_BUFFER_DATA (outbuf), out_processed, TRUE);
} else {
/* don't need to convert data format; process */
- err = resample->funcs->process (resample->state, NULL, &history_len,
+ err = resample->funcs->process (resample->state, NULL, &in_processed,
GST_BUFFER_DATA (outbuf), &out_processed);
}
@@ -848,12 +882,6 @@ gst_audio_resample_push_drain (GstAudioResample * resample)
return;
}
- if (G_UNLIKELY (out_processed == 0)) {
- GST_WARNING_OBJECT (resample, "Failed to get drain, dropping buffer");
- gst_buffer_unref (outbuf);
- return;
- }
-
/* time */
if (GST_CLOCK_TIME_IS_VALID (resample->t0)) {
GST_BUFFER_TIMESTAMP (outbuf) = resample->t0 +
@@ -876,7 +904,13 @@ gst_audio_resample_push_drain (GstAudioResample * resample)
}
/* move along */
resample->samples_out += out_processed;
- resample->samples_in += 0;
+ resample->samples_in += history_len;
+
+ if (G_UNLIKELY (out_processed == 0 && in_len * den > num)) {
+ GST_WARNING_OBJECT (resample, "Failed to get drain, dropping buffer");
+ gst_buffer_unref (outbuf);
+ return;
+ }
GST_BUFFER_SIZE (outbuf) =
out_processed * resample->channels * (resample->width / 8);
@@ -906,6 +940,11 @@ gst_audio_resample_event (GstBaseTransform * base, GstEvent * event)
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_FLUSH_STOP:
gst_audio_resample_reset_state (resample);
+ if (resample->state)
+ resample->count_gap = resample->funcs->get_filt_len (resample->state);
+ else
+ resample->count_gap = 0;
+ resample->count_nongap = 0;
resample->t0 = GST_CLOCK_TIME_NONE;
resample->in_offset0 = GST_BUFFER_OFFSET_NONE;
resample->out_offset0 = GST_BUFFER_OFFSET_NONE;
@@ -914,8 +953,14 @@ gst_audio_resample_event (GstBaseTransform * base, GstEvent * event)
resample->need_discont = TRUE;
break;
case GST_EVENT_NEWSEGMENT:
- gst_audio_resample_push_drain (resample);
+ if (resample->state)
+ gst_audio_resample_push_drain (resample, resample->count_nongap);
gst_audio_resample_reset_state (resample);
+ if (resample->state)
+ resample->count_gap = resample->funcs->get_filt_len (resample->state);
+ else
+ resample->count_gap = 0;
+ resample->count_nongap = 0;
resample->t0 = GST_CLOCK_TIME_NONE;
resample->in_offset0 = GST_BUFFER_OFFSET_NONE;
resample->out_offset0 = GST_BUFFER_OFFSET_NONE;
@@ -924,7 +969,8 @@ gst_audio_resample_event (GstBaseTransform * base, GstEvent * event)
resample->need_discont = TRUE;
break;
case GST_EVENT_EOS:
- gst_audio_resample_push_drain (resample);
+ if (resample->state)
+ gst_audio_resample_push_drain (resample, resample->count_nongap);
gst_audio_resample_reset_state (resample);
break;
default:
@@ -939,6 +985,9 @@ gst_audio_resample_check_discont (GstAudioResample * resample, GstBuffer * buf)
{
guint64 offset;
guint64 delta;
+ guint filt_len = resample->funcs->get_filt_len (resample->state);
+ guint64 delay =
+ gst_util_uint64_scale_round (filt_len, GST_SECOND, 2 * resample->inrate);
/* is the incoming buffer a discontinuity? */
if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf)))
@@ -952,7 +1001,7 @@ gst_audio_resample_check_discont (GstAudioResample * resample, GstBuffer * buf)
/* convert the inbound timestamp to an offset. */
offset =
gst_util_uint64_scale_int_round (GST_BUFFER_TIMESTAMP (buf) -
- resample->t0, resample->inrate, GST_SECOND);
+ resample->t0 - delay, resample->inrate, GST_SECOND);
/* many elements generate imperfect streams due to rounding errors, so we
* permit a small error (up to one sample) without triggering a filter
@@ -977,7 +1026,7 @@ gst_audio_resample_process (GstAudioResample * resample, GstBuffer * inbuf,
{
guint32 in_len, in_processed;
guint32 out_len, out_processed;
- gint err;
+ guint filt_len = resample->funcs->get_filt_len (resample->state);
in_len = GST_BUFFER_SIZE (inbuf) / resample->channels;
out_len = GST_BUFFER_SIZE (outbuf) / resample->channels;
@@ -988,47 +1037,92 @@ gst_audio_resample_process (GstAudioResample * resample, GstBuffer * inbuf,
in_processed = in_len;
out_processed = out_len;
- if (resample->funcs->width != resample->width) {
- /* need to convert data format for processing; ensure we have enough
- * workspace available */
- if (!gst_audio_resample_workspace_realloc (&resample->tmp_in,
- &resample->tmp_in_size, in_len * resample->channels *
- (resample->funcs->width / 8)) ||
- !gst_audio_resample_workspace_realloc (&resample->tmp_out,
- &resample->tmp_out_size, out_len * resample->channels *
- (resample->funcs->width / 8))) {
- GST_ERROR_OBJECT (resample, "failed to allocate workspace");
- return GST_FLOW_ERROR;
+ if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) {
+ resample->count_nongap = 0;
+ if (resample->count_gap < filt_len) {
+ guint zeros_to_push;
+ if (in_len >= filt_len - resample->count_gap)
+ zeros_to_push = filt_len - resample->count_gap;
+ else
+ zeros_to_push = in_len;
+
+ gst_audio_resample_push_drain (resample, zeros_to_push);
+ in_len -= zeros_to_push;
+ resample->count_gap += zeros_to_push;
}
- /* convert input */
- gst_audio_resample_convert_buffer (resample, GST_BUFFER_DATA (inbuf),
- resample->tmp_in, in_len, FALSE);
+ {
+ guint num, den;
+ resample->funcs->get_ratio (resample->state, &num, &den);
+ out_processed =
+ gst_util_uint64_scale_int_ceil (resample->samples_in + in_len, den,
+ num) - resample->samples_out;
+
+ memset (GST_BUFFER_DATA (outbuf), 0, GST_BUFFER_SIZE (outbuf));
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
+ resample->count_gap += in_len;
+ in_processed = in_len;
+ }
+ } else { /* not a gap */
- /* process */
- err = resample->funcs->process (resample->state,
- resample->tmp_in, &in_processed, resample->tmp_out, &out_processed);
+ gint err;
- /* convert output */
- gst_audio_resample_convert_buffer (resample, resample->tmp_out,
- GST_BUFFER_DATA (outbuf), out_processed, TRUE);
- } else {
- /* no format conversion required; process */
- err = resample->funcs->process (resample->state,
- GST_BUFFER_DATA (inbuf), &in_processed,
- GST_BUFFER_DATA (outbuf), &out_processed);
+ if (resample->count_gap > filt_len) {
+ /* push in enough zeros to restore the filter to the right offset */
+ guint num, den;
+ resample->funcs->get_ratio (resample->state, &num, &den);
+ gst_audio_resample_dump_drain (resample,
+ (resample->count_gap - filt_len) % num);
+ }
+ resample->count_gap = 0;
+ if (resample->count_nongap < filt_len) {
+ resample->count_nongap += in_len;
+ if (resample->count_nongap > filt_len)
+ resample->count_nongap = filt_len;
+ }
+
+ if (resample->funcs->width != resample->width) {
+ /* need to convert data format for processing; ensure we have enough
+ * workspace available */
+ if (!gst_audio_resample_workspace_realloc (&resample->tmp_in,
+ &resample->tmp_in_size, in_len * resample->channels *
+ (resample->funcs->width / 8)) ||
+ !gst_audio_resample_workspace_realloc (&resample->tmp_out,
+ &resample->tmp_out_size, out_len * resample->channels *
+ (resample->funcs->width / 8))) {
+ GST_ERROR_OBJECT (resample, "failed to allocate workspace");
+ return GST_FLOW_ERROR;
+ }
+
+ /* convert input */
+ gst_audio_resample_convert_buffer (resample, GST_BUFFER_DATA (inbuf),
+ resample->tmp_in, in_len, FALSE);
+
+ /* process */
+ err = resample->funcs->process (resample->state,
+ resample->tmp_in, &in_processed, resample->tmp_out, &out_processed);
+
+ /* convert output */
+ gst_audio_resample_convert_buffer (resample, resample->tmp_out,
+ GST_BUFFER_DATA (outbuf), out_processed, TRUE);
+ } else {
+ /* no format conversion required; process */
+ err = resample->funcs->process (resample->state,
+ GST_BUFFER_DATA (inbuf), &in_processed,
+ GST_BUFFER_DATA (outbuf), &out_processed);
+ }
+
+ if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) {
+ GST_ERROR_OBJECT (resample, "Failed to convert data: %s",
+ resample->funcs->strerror (err));
+ return GST_FLOW_ERROR;
+ }
}
/* 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 (err != RESAMPLER_ERR_SUCCESS)) {
- GST_ERROR_OBJECT (resample, "Failed to convert data: %s",
- resample->funcs->strerror (err));
- return GST_FLOW_ERROR;
- }
-
if (G_UNLIKELY (in_len != in_processed)) {
GST_WARNING_OBJECT (resample, "converted %d of %d input samples",
in_processed, in_len);
@@ -1115,13 +1209,17 @@ gst_audio_resample_transform (GstBaseTransform * base, GstBuffer * inbuf,
/* handle discontinuity */
if (G_UNLIKELY (resample->need_discont)) {
+ guint filt_len = resample->funcs->get_filt_len (resample->state);
+ guint64 delay = gst_util_uint64_scale_round (filt_len, GST_SECOND,
+ 2 * resample->inrate);
+ resample->count_gap = resample->funcs->get_filt_len (resample->state);
/* reset */
resample->samples_in = 0;
resample->samples_out = 0;
GST_DEBUG_OBJECT (resample, "found discontinuity; resyncing");
/* resync the timestamp and offset counters if possible */
if (GST_BUFFER_TIMESTAMP_IS_VALID (inbuf)) {
- resample->t0 = GST_BUFFER_TIMESTAMP (inbuf);
+ resample->t0 = GST_BUFFER_TIMESTAMP (inbuf) - delay;
} else {
GST_DEBUG_OBJECT (resample, "... but new timestamp is invalid");
resample->t0 = GST_CLOCK_TIME_NONE;
diff --git a/gst/audioresample/gstaudioresample.h b/gst/audioresample/gstaudioresample.h
index b0733365b..fdf3e06f0 100644
--- a/gst/audioresample/gstaudioresample.h
+++ b/gst/audioresample/gstaudioresample.h
@@ -63,6 +63,9 @@ struct _GstAudioResample {
guint64 out_offset0;
guint64 samples_in;
guint64 samples_out;
+
+ guint count_gap;
+ guint count_nongap;
gint channels;
gint inrate;
diff --git a/gst/audioresample/resample.c b/gst/audioresample/resample.c
index 2cfd5442e..7d42f0e0f 100644
--- a/gst/audioresample/resample.c
+++ b/gst/audioresample/resample.c
@@ -1311,6 +1311,12 @@ speex_resampler_get_output_latency (SpeexResamplerState * st)
}
EXPORT int
+speex_resampler_get_filt_len (SpeexResamplerState * st)
+{
+ return st->filt_len;
+}
+
+EXPORT int
speex_resampler_skip_zeros (SpeexResamplerState * st)
{
spx_uint32_t i;
diff --git a/gst/audioresample/speex_resampler.h b/gst/audioresample/speex_resampler.h
index 9dc02806a..894b380f8 100644
--- a/gst/audioresample/speex_resampler.h
+++ b/gst/audioresample/speex_resampler.h
@@ -73,6 +73,7 @@
#define speex_resampler_get_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_stride)
#define speex_resampler_get_input_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_latency)
#define speex_resampler_get_output_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_latency)
+#define speex_resampler_get_filt_len CAT_PREFIX(RANDOM_PREFIX,_resampler_get_filt_len)
#define speex_resampler_skip_zeros CAT_PREFIX(RANDOM_PREFIX,_resampler_skip_zeros)
#define speex_resampler_reset_mem CAT_PREFIX(RANDOM_PREFIX,_resampler_reset_mem)
#define speex_resampler_strerror CAT_PREFIX(RANDOM_PREFIX,_resampler_strerror)
@@ -333,6 +334,11 @@ int speex_resampler_get_input_latency(SpeexResamplerState *st);
*/
int speex_resampler_get_output_latency(SpeexResamplerState *st);
+/** Get the length of the filter in input samples.
+ * @param st Resampler state
+ */
+int speex_resampler_get_filt_len(SpeexResamplerState *st);
+
/** Make sure that the first samples to go out of the resamplers don't have
* leading zeros. This is only useful before starting to use a newly created
* resampler. It is recommended to use that when resampling an audio file, as
diff --git a/gst/audioresample/speex_resampler_wrapper.h b/gst/audioresample/speex_resampler_wrapper.h
index 36d444f87..08a82bc10 100644
--- a/gst/audioresample/speex_resampler_wrapper.h
+++ b/gst/audioresample/speex_resampler_wrapper.h
@@ -52,6 +52,7 @@ typedef struct {
void (*get_ratio) (SpeexResamplerState * st,
guint32 * ratio_num, guint32 * ratio_den);
int (*get_input_latency) (SpeexResamplerState * st);
+ int (*get_filt_len) (SpeexResamplerState * st);
int (*set_quality) (SpeexResamplerState * st, gint quality);
int (*reset_mem) (SpeexResamplerState * st);
int (*skip_zeros) (SpeexResamplerState * st);
@@ -71,6 +72,7 @@ void resample_float_resampler_get_rate (SpeexResamplerState * st,
void resample_float_resampler_get_ratio (SpeexResamplerState * st,
guint32 * ratio_num, guint32 * ratio_den);
int resample_float_resampler_get_input_latency (SpeexResamplerState * st);
+int resample_float_resampler_get_filt_len (SpeexResamplerState * st);
int resample_float_resampler_set_quality (SpeexResamplerState * st, gint quality);
int resample_float_resampler_reset_mem (SpeexResamplerState * st);
int resample_float_resampler_skip_zeros (SpeexResamplerState * st);
@@ -85,6 +87,7 @@ static const SpeexResampleFuncs float_funcs =
resample_float_resampler_get_rate,
resample_float_resampler_get_ratio,
resample_float_resampler_get_input_latency,
+ resample_float_resampler_get_filt_len,
resample_float_resampler_set_quality,
resample_float_resampler_reset_mem,
resample_float_resampler_skip_zeros,
@@ -104,6 +107,7 @@ void resample_double_resampler_get_rate (SpeexResamplerState * st,
void resample_double_resampler_get_ratio (SpeexResamplerState * st,
guint32 * ratio_num, guint32 * ratio_den);
int resample_double_resampler_get_input_latency (SpeexResamplerState * st);
+int resample_double_resampler_get_filt_len (SpeexResamplerState * st);
int resample_double_resampler_set_quality (SpeexResamplerState * st, gint quality);
int resample_double_resampler_reset_mem (SpeexResamplerState * st);
int resample_double_resampler_skip_zeros (SpeexResamplerState * st);
@@ -118,6 +122,7 @@ static const SpeexResampleFuncs double_funcs =
resample_double_resampler_get_rate,
resample_double_resampler_get_ratio,
resample_double_resampler_get_input_latency,
+ resample_double_resampler_get_filt_len,
resample_double_resampler_set_quality,
resample_double_resampler_reset_mem,
resample_double_resampler_skip_zeros,
@@ -137,6 +142,7 @@ void resample_int_resampler_get_rate (SpeexResamplerState * st,
void resample_int_resampler_get_ratio (SpeexResamplerState * st,
guint32 * ratio_num, guint32 * ratio_den);
int resample_int_resampler_get_input_latency (SpeexResamplerState * st);
+int resample_int_resampler_get_filt_len (SpeexResamplerState * st);
int resample_int_resampler_set_quality (SpeexResamplerState * st, gint quality);
int resample_int_resampler_reset_mem (SpeexResamplerState * st);
int resample_int_resampler_skip_zeros (SpeexResamplerState * st);
@@ -151,6 +157,7 @@ static const SpeexResampleFuncs int_funcs =
resample_int_resampler_get_rate,
resample_int_resampler_get_ratio,
resample_int_resampler_get_input_latency,
+ resample_int_resampler_get_filt_len,
resample_int_resampler_set_quality,
resample_int_resampler_reset_mem,
resample_int_resampler_skip_zeros,