mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 17:20:36 +00:00
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:
parent
babd0e5f5d
commit
ef9619200b
1 changed files with 141 additions and 0 deletions
|
@ -1203,6 +1203,8 @@ static GstStateChangeReturn gst_input_selector_change_state (GstElement *
|
|||
|
||||
static gboolean gst_input_selector_event (GstPad * pad, GstObject * parent,
|
||||
GstEvent * event);
|
||||
static gboolean gst_input_selector_query (GstPad * pad, GstObject * parent,
|
||||
GstQuery * query);
|
||||
|
||||
#define _do_init \
|
||||
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_pad_set_event_function (sel->srcpad,
|
||||
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_element_add_pad (GST_ELEMENT (sel), sel->srcpad);
|
||||
/* sinkpad management */
|
||||
|
@ -1580,6 +1584,143 @@ gst_input_selector_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
|||
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 */
|
||||
static inline gboolean
|
||||
gst_input_selector_is_active_sinkpad (GstInputSelector * sel, GstPad * pad)
|
||||
|
|
Loading…
Reference in a new issue