mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 01:00:37 +00:00
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:
parent
b5fe63ed79
commit
8b4f6dd43b
2 changed files with 39 additions and 3 deletions
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue