mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 18:21:04 +00:00
aggregator: add latency query handling
This commit is contained in:
parent
8a3993913f
commit
b9db635f48
3 changed files with 114 additions and 175 deletions
|
@ -226,6 +226,10 @@ struct _GstAggregatorPrivate
|
||||||
|
|
||||||
/* Lock to prevent two src setcaps from happening at the same time */
|
/* Lock to prevent two src setcaps from happening at the same time */
|
||||||
GMutex setcaps_lock;
|
GMutex setcaps_lock;
|
||||||
|
|
||||||
|
gboolean latency_live;
|
||||||
|
GstClockTime latency_min;
|
||||||
|
GstClockTime latency_max;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -904,6 +908,88 @@ _request_new_pad (GstElement * element,
|
||||||
return GST_PAD (agg_pad);
|
return GST_PAD (agg_pad);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
GstClockTime min, max;
|
||||||
|
gboolean live;
|
||||||
|
} LatencyData;
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_latency_query (GstAggregator * self, GstPad * pad, gpointer user_data)
|
||||||
|
{
|
||||||
|
LatencyData *data = user_data;
|
||||||
|
GstClockTime min, max;
|
||||||
|
GstQuery *query;
|
||||||
|
gboolean live, res;
|
||||||
|
|
||||||
|
query = gst_query_new_latency ();
|
||||||
|
res = gst_pad_peer_query (pad, query);
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
gst_query_parse_latency (query, &live, &min, &max);
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (self, "got latency live:%s min:%" G_GINT64_FORMAT
|
||||||
|
" max:%" G_GINT64_FORMAT, live ? "true" : "false", min, max);
|
||||||
|
|
||||||
|
if (min > data->min)
|
||||||
|
data->min = min;
|
||||||
|
|
||||||
|
if (max != GST_CLOCK_TIME_NONE &&
|
||||||
|
((data->max != GST_CLOCK_TIME_NONE && max < data->max) ||
|
||||||
|
(data->max == GST_CLOCK_TIME_NONE)))
|
||||||
|
data->max = max;
|
||||||
|
|
||||||
|
data->live |= live;
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_query_unref (query);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_aggregator_query_latency (GstAggregator * self, GstQuery * query)
|
||||||
|
{
|
||||||
|
LatencyData data;
|
||||||
|
|
||||||
|
data.min = 0;
|
||||||
|
data.max = GST_CLOCK_TIME_NONE;
|
||||||
|
data.live = FALSE;
|
||||||
|
|
||||||
|
/* query upstream's latency */
|
||||||
|
gst_aggregator_iterate_sinkpads (self,
|
||||||
|
(GstAggregatorPadForeachFunc) _latency_query, &data);
|
||||||
|
|
||||||
|
if (data.live && GST_CLOCK_TIME_IS_VALID (self->timeout) &&
|
||||||
|
self->timeout > data.max) {
|
||||||
|
GST_ELEMENT_WARNING (self, CORE, NEGOTIATION,
|
||||||
|
("%s", "Timeout too big"),
|
||||||
|
("The requested timeout value is too big for the latency in the "
|
||||||
|
"current pipeline. Limiting to %" G_GINT64_FORMAT, data.max));
|
||||||
|
self->timeout = data.max;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->priv->latency_live = data.live;
|
||||||
|
self->priv->latency_min = data.min;
|
||||||
|
self->priv->latency_max = data.max;
|
||||||
|
|
||||||
|
/* add our own */
|
||||||
|
if (GST_CLOCK_TIME_IS_VALID (self->timeout)) {
|
||||||
|
if (GST_CLOCK_TIME_IS_VALID (data.min))
|
||||||
|
data.min += self->timeout;
|
||||||
|
if (GST_CLOCK_TIME_IS_VALID (data.max))
|
||||||
|
data.max += self->timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (self, "configured latency live:%s min:%" G_GINT64_FORMAT
|
||||||
|
" max:%" G_GINT64_FORMAT, data.live ? "true" : "false", data.min,
|
||||||
|
data.max);
|
||||||
|
|
||||||
|
gst_query_set_latency (query, data.live, data.min, data.max);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
_send_event (GstElement * element, GstEvent * event)
|
_send_event (GstElement * element, GstEvent * event)
|
||||||
{
|
{
|
||||||
|
@ -951,6 +1037,10 @@ _src_query (GstAggregator * self, GstQuery * query)
|
||||||
|
|
||||||
goto discard;
|
goto discard;
|
||||||
}
|
}
|
||||||
|
case GST_QUERY_LATENCY:
|
||||||
|
{
|
||||||
|
return gst_aggregator_query_latency (self, query);
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1216,13 +1306,24 @@ gst_aggregator_dispose (GObject * object)
|
||||||
* as unresponsive.
|
* as unresponsive.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
gst_aggregator_set_timeout (GstAggregator * agg, gint64 timeout)
|
gst_aggregator_set_timeout (GstAggregator * self, gint64 timeout)
|
||||||
{
|
{
|
||||||
g_return_if_fail (GST_IS_AGGREGATOR (agg));
|
g_return_if_fail (GST_IS_AGGREGATOR (self));
|
||||||
|
|
||||||
GST_OBJECT_LOCK (agg);
|
GST_OBJECT_LOCK (self);
|
||||||
agg->timeout = timeout;
|
|
||||||
GST_OBJECT_UNLOCK (agg);
|
if (self->priv->latency_live && self->priv->latency_max != 0 &&
|
||||||
|
GST_CLOCK_TIME_IS_VALID (timeout) && timeout > self->priv->latency_max) {
|
||||||
|
GST_ELEMENT_WARNING (self, CORE, NEGOTIATION,
|
||||||
|
("%s", "Timeout too big"),
|
||||||
|
("The requested timeout value is too big for the latency in the "
|
||||||
|
"current pipeline. Limiting to %" G_GINT64_FORMAT,
|
||||||
|
self->priv->latency_max));
|
||||||
|
timeout = self->priv->latency_max;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->timeout = timeout;
|
||||||
|
GST_OBJECT_UNLOCK (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1343,6 +1444,10 @@ gst_aggregator_init (GstAggregator * self, GstAggregatorClass * klass)
|
||||||
|
|
||||||
priv->padcount = -1;
|
priv->padcount = -1;
|
||||||
priv->tags_changed = FALSE;
|
priv->tags_changed = FALSE;
|
||||||
|
|
||||||
|
self->priv->latency_live = FALSE;
|
||||||
|
self->priv->latency_min = 0;
|
||||||
|
self->priv->latency_max = GST_CLOCK_TIME_NONE;
|
||||||
_reset_flow_values (self);
|
_reset_flow_values (self);
|
||||||
|
|
||||||
AGGREGATOR_QUEUE (self) = g_async_queue_new ();
|
AGGREGATOR_QUEUE (self) = g_async_queue_new ();
|
||||||
|
|
|
@ -1324,87 +1324,6 @@ gst_videoaggregator_query_duration (GstVideoAggregator * vagg, GstQuery * query)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gst_videoaggregator_query_latency (GstVideoAggregator * vagg, GstQuery * query)
|
|
||||||
{
|
|
||||||
GstClockTime min, max;
|
|
||||||
gboolean live;
|
|
||||||
gboolean res;
|
|
||||||
GstIterator *it;
|
|
||||||
gboolean done;
|
|
||||||
GValue item = { 0 };
|
|
||||||
|
|
||||||
res = TRUE;
|
|
||||||
done = FALSE;
|
|
||||||
live = FALSE;
|
|
||||||
min = 0;
|
|
||||||
max = GST_CLOCK_TIME_NONE;
|
|
||||||
|
|
||||||
/* Take maximum of all latency values */
|
|
||||||
it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (vagg));
|
|
||||||
while (!done) {
|
|
||||||
switch (gst_iterator_next (it, &item)) {
|
|
||||||
case GST_ITERATOR_DONE:
|
|
||||||
done = TRUE;
|
|
||||||
break;
|
|
||||||
case GST_ITERATOR_OK:
|
|
||||||
{
|
|
||||||
GstPad *pad = g_value_get_object (&item);
|
|
||||||
GstQuery *peerquery;
|
|
||||||
GstClockTime min_cur, max_cur;
|
|
||||||
gboolean live_cur;
|
|
||||||
|
|
||||||
peerquery = gst_query_new_latency ();
|
|
||||||
|
|
||||||
/* Ask peer for latency */
|
|
||||||
res &= gst_pad_peer_query (pad, peerquery);
|
|
||||||
|
|
||||||
/* take max from all valid return values */
|
|
||||||
if (res) {
|
|
||||||
gst_query_parse_latency (peerquery, &live_cur, &min_cur, &max_cur);
|
|
||||||
|
|
||||||
if (min_cur > min)
|
|
||||||
min = min_cur;
|
|
||||||
|
|
||||||
if (max_cur != GST_CLOCK_TIME_NONE &&
|
|
||||||
((max != GST_CLOCK_TIME_NONE && max_cur > max) ||
|
|
||||||
(max == GST_CLOCK_TIME_NONE)))
|
|
||||||
max = max_cur;
|
|
||||||
|
|
||||||
live = live || live_cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
gst_query_unref (peerquery);
|
|
||||||
g_value_reset (&item);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case GST_ITERATOR_RESYNC:
|
|
||||||
live = FALSE;
|
|
||||||
min = 0;
|
|
||||||
max = GST_CLOCK_TIME_NONE;
|
|
||||||
res = TRUE;
|
|
||||||
gst_iterator_resync (it);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
res = FALSE;
|
|
||||||
done = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g_value_unset (&item);
|
|
||||||
gst_iterator_free (it);
|
|
||||||
|
|
||||||
if (res) {
|
|
||||||
/* store the results */
|
|
||||||
GST_DEBUG_OBJECT (vagg, "Calculated total latency: live %s, min %"
|
|
||||||
GST_TIME_FORMAT ", max %" GST_TIME_FORMAT,
|
|
||||||
(live ? "yes" : "no"), GST_TIME_ARGS (min), GST_TIME_ARGS (max));
|
|
||||||
gst_query_set_latency (query, live, min, max);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_videoaggregator_src_query (GstAggregator * agg, GstQuery * query)
|
gst_videoaggregator_src_query (GstAggregator * agg, GstQuery * query)
|
||||||
{
|
{
|
||||||
|
@ -1434,8 +1353,6 @@ gst_videoaggregator_src_query (GstAggregator * agg, GstQuery * query)
|
||||||
res = gst_videoaggregator_query_duration (vagg, query);
|
res = gst_videoaggregator_query_duration (vagg, query);
|
||||||
break;
|
break;
|
||||||
case GST_QUERY_LATENCY:
|
case GST_QUERY_LATENCY:
|
||||||
res = gst_videoaggregator_query_latency (vagg, query);
|
|
||||||
break;
|
|
||||||
case GST_QUERY_CAPS:
|
case GST_QUERY_CAPS:
|
||||||
res =
|
res =
|
||||||
GST_AGGREGATOR_CLASS (gst_videoaggregator_parent_class)->src_query
|
GST_AGGREGATOR_CLASS (gst_videoaggregator_parent_class)->src_query
|
||||||
|
|
|
@ -511,91 +511,6 @@ gst_audiomixer_query_duration (GstAudioMixer * audiomixer, GstQuery * query)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gst_audiomixer_query_latency (GstAudioMixer * audiomixer, GstQuery * query)
|
|
||||||
{
|
|
||||||
GstClockTime min, max;
|
|
||||||
gboolean live;
|
|
||||||
gboolean res;
|
|
||||||
GstIterator *it;
|
|
||||||
gboolean done;
|
|
||||||
GValue item = { 0, };
|
|
||||||
|
|
||||||
res = TRUE;
|
|
||||||
done = FALSE;
|
|
||||||
|
|
||||||
live = FALSE;
|
|
||||||
min = 0;
|
|
||||||
max = GST_CLOCK_TIME_NONE;
|
|
||||||
|
|
||||||
/* Take maximum of all latency values */
|
|
||||||
it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (audiomixer));
|
|
||||||
while (!done) {
|
|
||||||
GstIteratorResult ires;
|
|
||||||
|
|
||||||
ires = gst_iterator_next (it, &item);
|
|
||||||
switch (ires) {
|
|
||||||
case GST_ITERATOR_DONE:
|
|
||||||
done = TRUE;
|
|
||||||
break;
|
|
||||||
case GST_ITERATOR_OK:
|
|
||||||
{
|
|
||||||
GstPad *pad = g_value_get_object (&item);
|
|
||||||
GstQuery *peerquery;
|
|
||||||
GstClockTime min_cur, max_cur;
|
|
||||||
gboolean live_cur;
|
|
||||||
|
|
||||||
peerquery = gst_query_new_latency ();
|
|
||||||
|
|
||||||
/* Ask peer for latency */
|
|
||||||
res &= gst_pad_peer_query (pad, peerquery);
|
|
||||||
|
|
||||||
/* take max from all valid return values */
|
|
||||||
if (res) {
|
|
||||||
gst_query_parse_latency (peerquery, &live_cur, &min_cur, &max_cur);
|
|
||||||
|
|
||||||
if (min_cur > min)
|
|
||||||
min = min_cur;
|
|
||||||
|
|
||||||
if (max_cur != GST_CLOCK_TIME_NONE &&
|
|
||||||
((max != GST_CLOCK_TIME_NONE && max_cur > max) ||
|
|
||||||
(max == GST_CLOCK_TIME_NONE)))
|
|
||||||
max = max_cur;
|
|
||||||
|
|
||||||
live = live || live_cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
gst_query_unref (peerquery);
|
|
||||||
g_value_reset (&item);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case GST_ITERATOR_RESYNC:
|
|
||||||
live = FALSE;
|
|
||||||
min = 0;
|
|
||||||
max = GST_CLOCK_TIME_NONE;
|
|
||||||
res = TRUE;
|
|
||||||
gst_iterator_resync (it);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
res = FALSE;
|
|
||||||
done = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g_value_unset (&item);
|
|
||||||
gst_iterator_free (it);
|
|
||||||
|
|
||||||
if (res) {
|
|
||||||
/* store the results */
|
|
||||||
GST_DEBUG_OBJECT (audiomixer, "Calculated total latency: live %s, min %"
|
|
||||||
GST_TIME_FORMAT ", max %" GST_TIME_FORMAT,
|
|
||||||
(live ? "yes" : "no"), GST_TIME_ARGS (min), GST_TIME_ARGS (max));
|
|
||||||
gst_query_set_latency (query, live, min, max);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_audiomixer_src_query (GstAggregator * agg, GstQuery * query)
|
gst_audiomixer_src_query (GstAggregator * agg, GstQuery * query)
|
||||||
{
|
{
|
||||||
|
@ -628,7 +543,9 @@ gst_audiomixer_src_query (GstAggregator * agg, GstQuery * query)
|
||||||
res = gst_audiomixer_query_duration (audiomixer, query);
|
res = gst_audiomixer_query_duration (audiomixer, query);
|
||||||
break;
|
break;
|
||||||
case GST_QUERY_LATENCY:
|
case GST_QUERY_LATENCY:
|
||||||
res = gst_audiomixer_query_latency (audiomixer, query);
|
res =
|
||||||
|
GST_AGGREGATOR_CLASS (gst_audiomixer_parent_class)->src_query
|
||||||
|
(agg, query);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* FIXME, needs a custom query handler because we have multiple
|
/* FIXME, needs a custom query handler because we have multiple
|
||||||
|
@ -783,7 +700,7 @@ gst_audiomixer_sink_event (GstAggregator * agg, GstAggregatorPad * aggpad,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_audiomixer_reset (GstAudioMixer *audiomixer)
|
gst_audiomixer_reset (GstAudioMixer * audiomixer)
|
||||||
{
|
{
|
||||||
audiomixer->offset = 0;
|
audiomixer->offset = 0;
|
||||||
gst_caps_replace (&audiomixer->current_caps, NULL);
|
gst_caps_replace (&audiomixer->current_caps, NULL);
|
||||||
|
|
Loading…
Reference in a new issue