inputselector: Forward LATENCY query to all sinkpads

Otherwise downstream will consider the pipeline not live if the active
pad is live, even though some inactive pads might be live and might
require a non-zero latency configuration.

https://bugzilla.gnome.org/show_bug.cgi?id=796901
This commit is contained in:
Sebastian Dröge 2018-07-31 19:25:03 +03:00
parent babd0e5f5d
commit ef9619200b

View file

@ -1203,6 +1203,8 @@ static GstStateChangeReturn gst_input_selector_change_state (GstElement *
static gboolean gst_input_selector_event (GstPad * pad, GstObject * parent, static gboolean gst_input_selector_event (GstPad * pad, GstObject * parent,
GstEvent * event); GstEvent * event);
static gboolean gst_input_selector_query (GstPad * pad, GstObject * parent,
GstQuery * query);
#define _do_init \ #define _do_init \
GST_DEBUG_CATEGORY_INIT (input_selector_debug, \ GST_DEBUG_CATEGORY_INIT (input_selector_debug, \
@ -1311,6 +1313,8 @@ gst_input_selector_init (GstInputSelector * sel)
GST_DEBUG_FUNCPTR (gst_selector_pad_iterate_linked_pads)); GST_DEBUG_FUNCPTR (gst_selector_pad_iterate_linked_pads));
gst_pad_set_event_function (sel->srcpad, gst_pad_set_event_function (sel->srcpad,
GST_DEBUG_FUNCPTR (gst_input_selector_event)); GST_DEBUG_FUNCPTR (gst_input_selector_event));
gst_pad_set_query_function (sel->srcpad,
GST_DEBUG_FUNCPTR (gst_input_selector_query));
GST_OBJECT_FLAG_SET (sel->srcpad, GST_PAD_FLAG_PROXY_CAPS); GST_OBJECT_FLAG_SET (sel->srcpad, GST_PAD_FLAG_PROXY_CAPS);
gst_element_add_pad (GST_ELEMENT (sel), sel->srcpad); gst_element_add_pad (GST_ELEMENT (sel), sel->srcpad);
/* sinkpad management */ /* sinkpad management */
@ -1580,6 +1584,143 @@ gst_input_selector_event (GstPad * pad, GstObject * parent, GstEvent * event)
return result; return result;
} }
typedef struct
{
guint count;
gboolean live;
GstClockTime min, max;
} LatencyFoldData;
static gboolean
query_latency_default_fold (const GValue * item, GValue * ret,
gpointer user_data)
{
GstPad *pad = g_value_get_object (item), *peer;
LatencyFoldData *fold_data = user_data;
GstQuery *query;
gboolean res = FALSE;
query = gst_query_new_latency ();
peer = gst_pad_get_peer (pad);
if (peer) {
res = gst_pad_peer_query (pad, query);
} else {
GST_LOG_OBJECT (pad, "No peer pad found, ignoring this pad");
}
if (res) {
gboolean live;
GstClockTime min, max;
gst_query_parse_latency (query, &live, &min, &max);
GST_LOG_OBJECT (pad, "got latency live:%s min:%" G_GINT64_FORMAT
" max:%" G_GINT64_FORMAT, live ? "true" : "false", min, max);
/* FIXME : Why do we only take values into account if it's live ? */
if (live || fold_data->count == 0) {
if (min > fold_data->min)
fold_data->min = min;
if (fold_data->max == GST_CLOCK_TIME_NONE)
fold_data->max = max;
else if (max < fold_data->max)
fold_data->max = max;
fold_data->live = live;
}
fold_data->count += 1;
} else if (peer) {
GST_DEBUG_OBJECT (pad, "latency query failed");
g_value_set_boolean (ret, FALSE);
}
gst_query_unref (query);
if (peer)
gst_object_unref (peer);
return TRUE;
}
static gboolean
gst_input_selector_query_latency (GstInputSelector * sel, GstPad * pad,
GstQuery * query)
{
GstIterator *it;
GstIteratorResult res;
GValue ret = G_VALUE_INIT;
gboolean query_ret;
LatencyFoldData fold_data;
/* This is basically gst_pad_query_latency_default() but with a different
* iterator. We query all sinkpads! */
it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (sel));
if (!it) {
GST_DEBUG_OBJECT (pad, "Can't iterate internal links");
return FALSE;
}
g_value_init (&ret, G_TYPE_BOOLEAN);
retry:
fold_data.count = 0;
fold_data.live = FALSE;
fold_data.min = 0;
fold_data.max = GST_CLOCK_TIME_NONE;
g_value_set_boolean (&ret, TRUE);
res = gst_iterator_fold (it, query_latency_default_fold, &ret, &fold_data);
switch (res) {
case GST_ITERATOR_OK:
g_assert_not_reached ();
break;
case GST_ITERATOR_DONE:
break;
case GST_ITERATOR_ERROR:
g_value_set_boolean (&ret, FALSE);
break;
case GST_ITERATOR_RESYNC:
gst_iterator_resync (it);
goto retry;
default:
g_assert_not_reached ();
break;
}
gst_iterator_free (it);
query_ret = g_value_get_boolean (&ret);
if (query_ret) {
GST_LOG_OBJECT (pad, "got latency live:%s min:%" G_GINT64_FORMAT
" max:%" G_GINT64_FORMAT, fold_data.live ? "true" : "false",
fold_data.min, fold_data.max);
if (fold_data.min > fold_data.max) {
GST_ERROR_OBJECT (pad, "minimum latency bigger than maximum latency");
}
gst_query_set_latency (query, fold_data.live, fold_data.min, fold_data.max);
} else {
GST_LOG_OBJECT (pad, "latency query failed");
}
return query_ret;
}
static gboolean
gst_input_selector_query (GstPad * pad, GstObject * parent, GstQuery * query)
{
GstInputSelector *sel = GST_INPUT_SELECTOR (parent);
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_LATENCY:
/* Query all sink pads for the latency, not just the active one */
return gst_input_selector_query_latency (sel, pad, query);
default:
return gst_pad_query_default (pad, parent, query);
}
}
/* check if the pad is the active sinkpad */ /* check if the pad is the active sinkpad */
static inline gboolean static inline gboolean
gst_input_selector_is_active_sinkpad (GstInputSelector * sel, GstPad * pad) gst_input_selector_is_active_sinkpad (GstInputSelector * sel, GstPad * pad)