audiorate: add a tolerance property

It may not be uncommon for the input timestamps to experience some jitter
around the 'perfect time'.  As such, instead of regularly adding and dropping
samples, optionally allow for some tolerance in a more relaxed approach.

API: GstAudioRate:tolerance
This commit is contained in:
Mark Nauwelaerts 2009-12-15 18:41:38 +01:00
parent b5fe63ed79
commit 8b4f6dd43b
2 changed files with 39 additions and 3 deletions

View file

@ -30,8 +30,9 @@
* *
* The properties #GstAudioRate:in, #GstAudioRate:out, #GstAudioRate:add * The properties #GstAudioRate:in, #GstAudioRate:out, #GstAudioRate:add
* and #GstAudioRate:drop can be read to obtain information about number of * and #GstAudioRate:drop can be read to obtain information about number of
* input samples, output samples, dropped samples (i.e. the number of unused input * input samples, output samples, dropped samples (i.e. the number of unused
* samples) and inserted samples (i.e. the number of samples added to stream). * input samples) and inserted samples (i.e. the number of samples added to
* stream).
* *
* When the #GstAudioRate:silent property is set to FALSE, a GObject property * When the #GstAudioRate:silent property is set to FALSE, a GObject property
* notification will be emitted whenever one of the #GstAudioRate:add or * notification will be emitted whenever one of the #GstAudioRate:add or
@ -40,6 +41,13 @@
* Note that property notification will happen from the streaming thread, so * Note that property notification will happen from the streaming thread, so
* applications should be prepared for this. * applications should be prepared for this.
* *
* If the #GstAudioRate:tolerance property is non-zero, and an incoming buffer's
* timestamp deviates less than the property indicates from what would make a
* 'perfect time', then no samples will be added or dropped.
* Note that the output is still guaranteed to be a perfect stream, which means
* that the incoming data is then simply shifted (by less than the indicated
* tolerance) to a perfect time.
*
* <refsect2> * <refsect2>
* <title>Example pipelines</title> * <title>Example pipelines</title>
* |[ * |[
@ -75,7 +83,8 @@ enum
LAST_SIGNAL LAST_SIGNAL
}; };
#define DEFAULT_SILENT TRUE #define DEFAULT_SILENT TRUE
#define DEFAULT_TOLERANCE 0
enum enum
{ {
@ -85,6 +94,7 @@ enum
ARG_ADD, ARG_ADD,
ARG_DROP, ARG_DROP,
ARG_SILENT, ARG_SILENT,
ARG_TOLERANCE,
/* FILL ME */ /* FILL ME */
}; };
@ -189,6 +199,11 @@ gst_audio_rate_class_init (GstAudioRateClass * klass)
g_param_spec_boolean ("silent", "silent", g_param_spec_boolean ("silent", "silent",
"Don't emit notify for dropped and duplicated frames", DEFAULT_SILENT, "Don't emit notify for dropped and duplicated frames", DEFAULT_SILENT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, ARG_TOLERANCE,
g_param_spec_uint64 ("tolerance", "tolerance",
"Only act if timestamp jitter/imperfection exceeds indicated tolerance (ns)",
0, G_MAXUINT64, DEFAULT_TOLERANCE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
element_class->change_state = gst_audio_rate_change_state; element_class->change_state = gst_audio_rate_change_state;
} }
@ -277,6 +292,7 @@ gst_audio_rate_init (GstAudioRate * audiorate)
audiorate->drop = 0; audiorate->drop = 0;
audiorate->add = 0; audiorate->add = 0;
audiorate->silent = DEFAULT_SILENT; audiorate->silent = DEFAULT_SILENT;
audiorate->tolerance = DEFAULT_TOLERANCE;
} }
static void static void
@ -479,6 +495,7 @@ gst_audio_rate_chain (GstPad * pad, GstBuffer * buf)
guint64 in_offset, in_offset_end, in_samples; guint64 in_offset, in_offset_end, in_samples;
guint in_size; guint in_size;
GstFlowReturn ret = GST_FLOW_OK; GstFlowReturn ret = GST_FLOW_OK;
GstClockTimeDiff diff;
audiorate = GST_AUDIO_RATE (gst_pad_get_parent (pad)); audiorate = GST_AUDIO_RATE (gst_pad_get_parent (pad));
@ -536,6 +553,17 @@ gst_audio_rate_chain (GstPad * pad, GstBuffer * buf)
GST_TIME_ARGS (GST_FRAMES_TO_CLOCK_TIME (in_samples, audiorate->rate)), GST_TIME_ARGS (GST_FRAMES_TO_CLOCK_TIME (in_samples, audiorate->rate)),
in_size, in_offset, in_offset_end, audiorate->next_offset); in_size, in_offset, in_offset_end, audiorate->next_offset);
diff = in_time - audiorate->next_ts;
if (diff <= (GstClockTimeDiff) audiorate->tolerance &&
diff >= (GstClockTimeDiff) - audiorate->tolerance) {
/* buffer time close enough to expected time,
* so produce a perfect stream by simply 'shifting'
* it to next ts and offset and sending */
GST_LOG_OBJECT (audiorate, "within tolerance %" GST_TIME_FORMAT,
GST_TIME_ARGS (audiorate->tolerance));
goto send;
}
/* do we need to insert samples */ /* do we need to insert samples */
if (in_offset > audiorate->next_offset) { if (in_offset > audiorate->next_offset) {
GstBuffer *fill; GstBuffer *fill;
@ -639,6 +667,7 @@ gst_audio_rate_chain (GstPad * pad, GstBuffer * buf)
if (GST_BUFFER_SIZE (buf) == 0) if (GST_BUFFER_SIZE (buf) == 0)
goto beach; goto beach;
send:
/* Now calculate parameters for whichever buffer (either the original /* Now calculate parameters for whichever buffer (either the original
* or truncated one) we're pushing. */ * or truncated one) we're pushing. */
GST_BUFFER_OFFSET (buf) = audiorate->next_offset; GST_BUFFER_OFFSET (buf) = audiorate->next_offset;
@ -696,6 +725,9 @@ gst_audio_rate_set_property (GObject * object,
case ARG_SILENT: case ARG_SILENT:
audiorate->silent = g_value_get_boolean (value); audiorate->silent = g_value_get_boolean (value);
break; break;
case ARG_TOLERANCE:
audiorate->tolerance = g_value_get_uint64 (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -724,6 +756,9 @@ gst_audio_rate_get_property (GObject * object,
case ARG_SILENT: case ARG_SILENT:
g_value_set_boolean (value, audiorate->silent); g_value_set_boolean (value, audiorate->silent);
break; break;
case ARG_TOLERANCE:
g_value_set_uint64 (value, audiorate->tolerance);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;

View file

@ -57,6 +57,7 @@ struct _GstAudioRate
/* stats */ /* stats */
guint64 in, out, add, drop; guint64 in, out, add, drop;
gboolean silent; gboolean silent;
guint64 tolerance;
/* audio state */ /* audio state */
guint64 next_offset; guint64 next_offset;