soundtouch: Handling incoming rate when requested.

Absorb inbound segments with rate != 1.0 and output a segment with
rate taken from the new output-rate property, adjusting the segment
applied_rate, stream duration and timestamps as necessary to
compensate
This commit is contained in:
Jan Schmidt 2011-08-30 17:43:22 +10:00
parent 436620fff9
commit 8fbf3a3129
2 changed files with 49 additions and 9 deletions

View file

@ -55,6 +55,7 @@ struct _GstPitchPrivate
enum
{
ARG_0,
ARG_OUT_RATE,
ARG_RATE,
ARG_TEMPO,
ARG_PITCH
@ -147,6 +148,11 @@ gst_pitch_class_init (GstPitchClass * klass)
"Audio stream rate", 0.1, 10.0, 1.0,
(GParamFlags) (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)));
g_object_class_install_property (gobject_class, ARG_OUT_RATE,
g_param_spec_float ("output-rate", "Output Rate",
"Output rate on downstream segment events", 0.1, 10.0, 1.0,
(GParamFlags) (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)));
g_type_class_add_private (gobject_class, sizeof (GstPitchPrivate));
}
@ -186,12 +192,14 @@ gst_pitch_init (GstPitch * pitch, GstPitchClass * pitch_class)
pitch->tempo = 1.0;
pitch->rate = 1.0;
pitch->out_seg_rate = 1.0;
pitch->seg_arate = 1.0;
pitch->pitch = 1.0;
pitch->next_buffer_time = 0;
pitch->next_buffer_offset = 0;
pitch->priv->st->setRate (pitch->rate);
pitch->priv->st->setTempo (pitch->tempo);
pitch->priv->st->setTempo (pitch->tempo * pitch->seg_arate);
pitch->priv->st->setPitch (pitch->pitch);
pitch->priv->stream_time_ratio = 1.0;
@ -232,18 +240,22 @@ gst_pitch_set_property (GObject * object, guint prop_id,
switch (prop_id) {
case ARG_TEMPO:
pitch->tempo = g_value_get_float (value);
pitch->priv->stream_time_ratio = pitch->tempo * pitch->rate;
pitch->priv->st->setTempo (pitch->tempo);
pitch->priv->stream_time_ratio = pitch->tempo * pitch->rate * pitch->seg_arate;
pitch->priv->st->setTempo (pitch->tempo * pitch->seg_arate);
GST_OBJECT_UNLOCK (pitch);
gst_pitch_update_duration (pitch);
break;
case ARG_RATE:
pitch->rate = g_value_get_float (value);
pitch->priv->stream_time_ratio = pitch->tempo * pitch->rate;
pitch->priv->stream_time_ratio = pitch->tempo * pitch->rate * pitch->seg_arate;
pitch->priv->st->setRate (pitch->rate);
GST_OBJECT_UNLOCK (pitch);
gst_pitch_update_duration (pitch);
break;
case ARG_OUT_RATE:
/* Has no effect until the next input segment */
pitch->out_seg_rate = g_value_get_float (value);
GST_OBJECT_UNLOCK (pitch);
case ARG_PITCH:
pitch->pitch = g_value_get_float (value);
pitch->priv->st->setPitch (pitch->pitch);
@ -270,6 +282,9 @@ gst_pitch_get_property (GObject * object, guint prop_id,
case ARG_RATE:
g_value_set_float (value, pitch->rate);
break;
case ARG_OUT_RATE:
g_value_set_float (value, pitch->out_seg_rate);
break;
case ARG_PITCH:
g_value_set_float (value, pitch->pitch);
break;
@ -695,16 +710,17 @@ gst_pitch_process_segment (GstPitch * pitch, GstEvent ** event)
gint64 start_value, stop_value, base;
gint64 next_offset = 0, next_time = 0;
gboolean update = FALSE;
gdouble rate;
gdouble rate, out_seg_rate, arate, our_arate;
gfloat stream_time_ratio;
g_return_val_if_fail (event, FALSE);
GST_OBJECT_LOCK (pitch);
stream_time_ratio = pitch->priv->stream_time_ratio;
out_seg_rate = pitch->out_seg_rate;
GST_OBJECT_UNLOCK (pitch);
gst_event_parse_new_segment (*event, &update, &rate, &format, &start_value,
gst_event_parse_new_segment_full (*event, &update, &rate, &arate, &format, &start_value,
&stop_value, &base);
if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT) {
@ -713,21 +729,36 @@ gst_pitch_process_segment (GstPitch * pitch, GstEvent ** event)
"open ended NEWSEGMENT in TIME format.");
gst_event_unref (*event);
*event =
gst_event_new_new_segment (update, rate, GST_FORMAT_TIME, 0, -1, 0);
gst_event_new_new_segment_full (update, rate, arate, GST_FORMAT_TIME, 0, -1, 0);
start_value = 0;
stop_value = -1;
base = 0;
}
/* Figure out how much of the incoming 'rate' we'll apply ourselves */
our_arate = rate / out_seg_rate;
/* update the output rate variables */
rate = out_seg_rate;
arate *= our_arate;
GST_LOG_OBJECT (pitch->sinkpad,
"segment %" G_GINT64_FORMAT " - %" G_GINT64_FORMAT " (%d)", start_value,
stop_value, format);
stream_time_ratio = pitch->tempo * pitch->rate * pitch->seg_arate;
if (stream_time_ratio == 0) {
GST_LOG_OBJECT (pitch->sinkpad, "stream_time_ratio is zero");
return FALSE;
}
/* Update the playback rate */
GST_OBJECT_LOCK (pitch);
pitch->seg_arate = our_arate;
pitch->priv->stream_time_ratio = stream_time_ratio;
pitch->priv->st->setTempo (pitch->tempo * pitch->seg_arate);
GST_OBJECT_UNLOCK (pitch);
start_value = (gint64) (start_value / stream_time_ratio);
if (stop_value != -1)
stop_value = (gint64) (stop_value / stream_time_ratio);
@ -752,8 +783,8 @@ gst_pitch_process_segment (GstPitch * pitch, GstEvent ** event)
pitch->next_buffer_offset = next_offset;
gst_event_unref (*event);
*event = gst_event_new_new_segment (update, rate, format, start_value,
stop_value, base);
*event = gst_event_new_new_segment_full (update, rate, arate, format,
start_value, stop_value, base);
return TRUE;
}
@ -772,6 +803,8 @@ gst_pitch_sink_event (GstPad * pad, GstEvent * event)
case GST_EVENT_FLUSH_STOP:
gst_pitch_flush_buffer (pitch, FALSE);
pitch->priv->st->clear ();
pitch->next_buffer_offset = 0;
pitch->next_buffer_time = 0;
pitch->min_latency = pitch->max_latency = 0;
break;
case GST_EVENT_EOS:

View file

@ -58,11 +58,18 @@ struct _GstPitch
* > 1 makes the stream shorter
*/
gfloat out_seg_rate; /* change output segment rate
* Affects playback when input
* segments have rate != out_rate
*/
gfloat pitch; /* change pitch
* change the pitch without affecting the
* duration, stream length doesn't change
*/
gfloat seg_arate; /* Rate to apply from input segment */
/* values extracted from caps */
gint samplerate; /* samplerate */
gint channels; /* number of audio channels */