gst_pad_query_default以及gst_pad_event_default
我们知道event和query可以在管道中流动(上游/下游),但是元件内部是如何流动的呢?也就是
如何从元件的srcpad流动到sinpad?
1.gst_pad_event_default函数
/*** gst_pad_event_default:* @pad: a #GstPad to call the default event handler on.* @parent: (allow-none): the parent of @pad or %NULL* @event: (transfer full): the #GstEvent to handle.** Invokes the default event handler for the given pad.** The EOS event will pause the task associated with @pad before it is forwarded* to all internally linked pads,** The event is sent to all pads internally linked to @pad. This function* takes ownership of @event.** Returns: %TRUE if the event was sent successfully.*/
gboolean
gst_pad_event_default (GstPad * pad, GstObject * parent, GstEvent * event)
{gboolean result, forward = TRUE;g_return_val_if_fail (GST_IS_PAD (pad), FALSE);g_return_val_if_fail (event != NULL, FALSE);GST_LOG_OBJECT (pad, "default event handler for event %" GST_PTR_FORMAT,event);switch (GST_EVENT_TYPE (event)) {case GST_EVENT_CAPS:forward = GST_PAD_IS_PROXY_CAPS (pad);result = TRUE;break;default:break;}if (forward) {EventData data;data.event = event;data.dispatched = FALSE;data.result = FALSE;gst_pad_forward (pad, (GstPadForwardFunction) event_forward_func, &data);/* for sinkpads without a parent element or without internal links, nothing* will be dispatched but we still want to return TRUE. */if (data.dispatched)result = data.result;elseresult = TRUE;}gst_event_unref (event);return result;
}
关键流程:
1.对于GST_EVENT_CAPS事件,需要判断是否是GST_PAD_IS_PROXY_CAPS(pad)
2.gst_pad_forward,这里就是event在元件内部流动的函数
static gboolean
event_forward_func (GstPad * pad, EventData * data)
{/* for each pad we send to, we should ref the event; it's up* to downstream to unref again when handled. */GST_LOG_OBJECT (pad, "Reffing and pushing event %p (%s) to %s:%s",data->event, GST_EVENT_TYPE_NAME (data->event), GST_DEBUG_PAD_NAME (pad));data->result |= gst_pad_push_event (pad, gst_event_ref (data->event));data->dispatched = TRUE;/* don't stop */return FALSE;
}
注册的event_forward_func函明确就是,push事件到对应的pad.
/*** gst_pad_forward:* @pad: a #GstPad* @forward: (scope call): a #GstPadForwardFunction* @user_data: user data passed to @forward** Calls @forward for all internally linked pads of @pad. This function deals with* dynamically changing internal pads and will make sure that the @forward* function is only called once for each pad.** When @forward returns %TRUE, no further pads will be processed.** Returns: %TRUE if one of the dispatcher functions returned %TRUE.*/
gboolean
gst_pad_forward (GstPad * pad, GstPadForwardFunction forward,gpointer user_data)
{gboolean result = FALSE;GstIterator *iter;gboolean done = FALSE;GValue item = { 0, };GList *pushed_pads = NULL;iter = gst_pad_iterate_internal_links (pad);if (!iter)goto no_iter;while (!done) {switch (gst_iterator_next (iter, &item)) {case GST_ITERATOR_OK:{GstPad *intpad;intpad = g_value_get_object (&item);/* if already pushed, skip. FIXME, find something faster to tag pads */if (intpad == NULL || g_list_find (pushed_pads, intpad)) {g_value_reset (&item);break;}GST_LOG_OBJECT (pad, "calling forward function on pad %s:%s",GST_DEBUG_PAD_NAME (intpad));done = result = forward (intpad, user_data);pushed_pads = g_list_prepend (pushed_pads, intpad);g_value_reset (&item);break;}case GST_ITERATOR_RESYNC:/* We don't reset the result here because we don't push the event* again on pads that got the event already and because we need* to consider the result of the previous pushes */gst_iterator_resync (iter);break;case GST_ITERATOR_ERROR:GST_ERROR_OBJECT (pad, "Could not iterate over internally linked pads");done = TRUE;break;case GST_ITERATOR_DONE:done = TRUE;break;}}g_value_unset (&item);gst_iterator_free (iter);g_list_free (pushed_pads);no_iter:return result;
}
顾名思义 Calls @forward for all internally linked pads of @pad,如何实现的呢?
关键流程:gst_pad_iterate_internal_links
/*** gst_pad_iterate_internal_links:* @pad: the GstPad to get the internal links of.** Gets an iterator for the pads to which the given pad is linked to inside* of the parent element.** Each #GstPad element yielded by the iterator will have its refcount increased,* so unref after use.** Free-function: gst_iterator_free** Returns: (transfer full) (nullable): a new #GstIterator of #GstPad* or %NULL when the pad does not have an iterator function* configured. Use gst_iterator_free() after usage.*/
GstIterator *
gst_pad_iterate_internal_links (GstPad * pad)
{GstIterator *res = NULL;GstObject *parent;g_return_val_if_fail (GST_IS_PAD (pad), NULL);GST_OBJECT_LOCK (pad);ACQUIRE_PARENT (pad, parent, no_parent);GST_OBJECT_UNLOCK (pad);if (GST_PAD_ITERINTLINKFUNC (pad))res = GST_PAD_ITERINTLINKFUNC (pad) (pad, parent);RELEASE_PARENT (parent);return res;/* ERRORS */
no_parent:{GST_DEBUG_OBJECT (pad, "no parent");GST_OBJECT_UNLOCK (pad);return NULL;}
}
也就是获取当前pad的内部linked的pad,这里可以看到是调用pad的GST_PAD_ITERINTLINKFUNC
函数。这个函数是可以被重写的,我们以multiqueue插件为例
gst_pad_set_chain_function (sinkpad,GST_DEBUG_FUNCPTR (gst_multi_queue_chain));gst_pad_set_activatemode_function (sinkpad,GST_DEBUG_FUNCPTR (gst_multi_queue_sink_activate_mode));gst_pad_set_event_full_function (sinkpad,GST_DEBUG_FUNCPTR (gst_multi_queue_sink_event));gst_pad_set_query_function (sinkpad,GST_DEBUG_FUNCPTR (gst_multi_queue_sink_query));gst_pad_set_iterate_internal_links_function (sinkpad,GST_DEBUG_FUNCPTR (gst_multi_queue_iterate_internal_links)); //设置了iterate_internal_links函数GST_OBJECT_FLAG_SET (sinkpad, GST_PAD_FLAG_PROXY_CAPS);
gst_multi_queue_iterate_internal_links (GstPad * pad, GstObject * parent)
{GstIterator *it = NULL;GstPad *opad, *sinkpad, *srcpad;GstSingleQueue *squeue;GstMultiQueue *mq = GST_MULTI_QUEUE (parent);GValue val = { 0, };GST_MULTI_QUEUE_MUTEX_LOCK (mq);squeue = GST_MULTIQUEUE_PAD (pad)->sq;if (!squeue)goto out;srcpad = g_weak_ref_get (&squeue->srcpad);sinkpad = g_weak_ref_get (&squeue->sinkpad);if (sinkpad == pad && srcpad) {opad = srcpad;gst_clear_object (&sinkpad);} else if (srcpad == pad && sinkpad) {opad = sinkpad;gst_clear_object (&srcpad);} else {gst_clear_object (&srcpad);gst_clear_object (&sinkpad);goto out;}g_value_init (&val, GST_TYPE_PAD);g_value_set_object (&val, opad);it = gst_iterator_new_single (GST_TYPE_PAD, &val);g_value_unset (&val);gst_object_unref (opad);out:GST_MULTI_QUEUE_MUTEX_UNLOCK (mq);return it;
}
可以知道如果参数sinkpad会返回对应的scrpad。反之亦然。
那我们再看下默认函数gst_pad_iterate_internal_links_default
/*** gst_pad_iterate_internal_links_default:* @pad: the #GstPad to get the internal links of.* @parent: (allow-none): the parent of @pad or %NULL** Iterate the list of pads to which the given pad is linked to inside of* the parent element.* This is the default handler, and thus returns an iterator of all of the* pads inside the parent element with opposite direction.** The caller must free this iterator after use with gst_iterator_free().** Returns: (nullable): a #GstIterator of #GstPad, or %NULL if @pad* has no parent. Unref each returned pad with gst_object_unref().*/
GstIterator *
gst_pad_iterate_internal_links_default (GstPad * pad, GstObject * parent)
{GstIterator *res;GList **padlist;guint32 *cookie;GMutex *lock;gpointer owner;GstElement *eparent;g_return_val_if_fail (GST_IS_PAD (pad), NULL);if (parent != NULL && GST_IS_ELEMENT (parent)) {eparent = GST_ELEMENT_CAST (gst_object_ref (parent));} else {GST_OBJECT_LOCK (pad);eparent = GST_PAD_PARENT (pad);if (!eparent || !GST_IS_ELEMENT (eparent))goto no_parent;gst_object_ref (eparent);GST_OBJECT_UNLOCK (pad);}if (pad->direction == GST_PAD_SRC)padlist = &eparent->sinkpads;elsepadlist = &eparent->srcpads;GST_DEBUG_OBJECT (pad, "Making iterator");cookie = &eparent->pads_cookie;owner = eparent;lock = GST_OBJECT_GET_LOCK (eparent);res = gst_iterator_new_list (GST_TYPE_PAD,lock, cookie, padlist, (GObject *) owner, NULL);gst_object_unref (owner);return res;/* ERRORS */
no_parent:{GST_OBJECT_UNLOCK (pad);GST_DEBUG_OBJECT (pad, "no parent element");return NULL;}
}
逻辑可以获取到该元件的padlist,这里就会出现一个问题。如果该元件有多个srcpad或者sinkpad
那么内部流动就会出现问题了?因为gst_pad_forward只要有一个push成功就会跳出循环了,
所以这种场景就需要我们自定义gst_pad_iterate_internal_links函数了。
if (pad->direction == GST_PAD_SRC)padlist = &eparent->sinkpads;elsepadlist = &eparent->srcpads;
=========================================================================
2.在看下gst_pad_query_default基本逻辑是一样的,注意下某些事件的forward条件限制。
/*** gst_pad_query_default:* @pad: a #GstPad to call the default query handler on.* @parent: (allow-none): the parent of @pad or %NULL* @query: (transfer none): the #GstQuery to handle.** Invokes the default query handler for the given pad.* The query is sent to all pads internally linked to @pad. Note that* if there are many possible sink pads that are internally linked to* @pad, only one will be sent the query.* Multi-sinkpad elements should implement custom query handlers.** Returns: %TRUE if the query was performed successfully.*/
gboolean
gst_pad_query_default (GstPad * pad, GstObject * parent, GstQuery * query)
{gboolean forward, ret = FALSE;switch (GST_QUERY_TYPE (query)) {case GST_QUERY_SCHEDULING:forward = GST_PAD_IS_PROXY_SCHEDULING (pad);break;case GST_QUERY_ALLOCATION:forward = GST_PAD_IS_PROXY_ALLOCATION (pad);break;case GST_QUERY_ACCEPT_CAPS:ret = gst_pad_query_accept_caps_default (pad, query);forward = FALSE;break;case GST_QUERY_CAPS:ret = gst_pad_query_caps_default (pad, query);forward = FALSE;break;case GST_QUERY_LATENCY:ret = gst_pad_query_latency_default (pad, query);forward = FALSE;break;case GST_QUERY_BITRATE:/* FIXME: better default handling */forward = TRUE;break;case GST_QUERY_POSITION:case GST_QUERY_SEEKING:case GST_QUERY_FORMATS:case GST_QUERY_JITTER:case GST_QUERY_RATE:case GST_QUERY_CONVERT:default:forward = TRUE;break;}GST_DEBUG_OBJECT (pad, "%sforwarding %p (%s) query", (forward ? "" : "not "),query, GST_QUERY_TYPE_NAME (query));if (forward) {QueryData data;data.query = query;data.dispatched = FALSE;data.result = FALSE;gst_pad_forward (pad, (GstPadForwardFunction) query_forward_func, &data);if (data.dispatched) {ret = data.result;} else {/* nothing dispatched, assume drained */if (GST_QUERY_TYPE (query) == GST_QUERY_DRAIN)ret = TRUE;elseret = FALSE;}}return ret;
}
static gboolean
query_forward_func (GstPad * pad, QueryData * data)
{GST_LOG_OBJECT (pad, "query peer %p (%s) of %s:%s",data->query, GST_QUERY_TYPE_NAME (data->query), GST_DEBUG_PAD_NAME (pad));data->result |= gst_pad_peer_query (pad, data->query);data->dispatched = TRUE;/* stop on first successful reply */return data->result;
}
整理:
1、GST_QUERY_SCHEDULING,条件forward = GST_PAD_IS_PROXY_SCHEDULING (pad);
2、GST_QUERY_ALLOCATION,条件GST_PAD_IS_PROXY_ALLOCATION (pad);
3、GST_QUERY_ACCEPT_CAPS、GST_QUERY_CAPS、GST_QUERY_LATENCY、
GST_QUERY_BITRATE 这些时间无法进行forward查询
4、其他无限制,默认是可以进行forward查询