前言:
pad 是每个 element实例 都有的,是 elemenet 之间沟通的代理人,没有 pad 的 element 没法于其他element交流。
考虑到gstreamer存在继承体系,那么如果继承类element不在init函数里创建pad,那么在gst_element_link的时候是否可以使用父类element实例的pad呢? 下面从源码来找答案。
gst_element_link
在 gstutils.c 找到 gst_element_link(...) 的实现。
/**
* gst_element_link:
* @src: (transfer none): a #GstElement containing the source pad.
* @dest: (transfer none): the #GstElement containing the destination pad.
*
* Links @src to @dest. The link must be from source to
* destination; the other direction will not be tried. The function looks for
* existing pads that aren't linked yet. It will request new pads if necessary.
* Such pads need to be released manually when unlinking.
* If multiple links are possible, only one is established.
*
* Make sure you have added your elements to a bin or pipeline with
* gst_bin_add() before trying to link them.
*
* Returns: %TRUE if the elements could be linked, %FALSE otherwise.
*/
gboolean
gst_element_link (GstElement * src, GstElement * dest)
{
return gst_element_link_pads (src, NULL, dest, NULL);
}
直接调用 gst_element_link_pads(...) , 同样在 gstutils.c ,入参为上有element和下游element 。
gst_element_link_pads
实现同样在 gstutils.c 里。
/**
* gst_element_link_pads:
* @src: a #GstElement containing the source pad.
* @srcpadname: (nullable): the name of the #GstPad in source element
* or %NULL for any pad.
* @dest: (transfer none): the #GstElement containing the destination pad.
* @destpadname: (nullable): the name of the #GstPad in destination element,
* or %NULL for any pad.
*
* Links the two named pads of the source and destination elements.
* Side effect is that if one of the pads has no parent, it becomes a
* child of the parent of the other element. If they have different
* parents, the link fails.
*
* Returns: %TRUE if the pads could be linked, %FALSE otherwise.
*/
gboolean
gst_element_link_pads (GstElement * src, const gchar * srcpadname,
GstElement * dest, const gchar * destpadname)
{
return gst_element_link_pads_full (src, srcpadname, dest, destpadname,
GST_PAD_LINK_CHECK_DEFAULT);
}
回到gst_element_link,第二个和第四个参数为NULL,结合gst_element_link_pads,第二个和第四个参数为padname,因此gst_element_link的行为就是“链接两个element,不在两个element中指定使用哪些pad实例进行互相链接”。
gst_element_link_pads_full
这个函数有点长,我们节选,全文同样在 gstutils.c 里。
定义及注释说明,暂且略过。
/**
* gst_element_link_pads_full:
* @src: a #GstElement containing the source pad.
* @srcpadname: (nullable): the name of the #GstPad in source element
* or %NULL for any pad.
* @dest: (transfer none): the #GstElement containing the destination pad.
* @destpadname: (nullable): the name of the #GstPad in destination element,
* or %NULL for any pad.
* @flags: the #GstPadLinkCheck to be performed when linking pads.
*
* Links the two named pads of the source and destination elements.
* Side effect is that if one of the pads has no parent, it becomes a
* child of the parent of the other element. If they have different
* parents, the link fails.
*
* Calling gst_element_link_pads_full() with @flags == %GST_PAD_LINK_CHECK_DEFAULT
* is the same as calling gst_element_link_pads() and the recommended way of
* linking pads with safety checks applied.
*
* This is a convenience function for gst_pad_link_full().
*
* Returns: %TRUE if the pads could be linked, %FALSE otherwise.
*/
gboolean
gst_element_link_pads_full (GstElement * src, const gchar * srcpadname,
GstElement * dest, const gchar * destpadname, GstPadLinkCheck flags)
如果指定了上游element的padname
则在上游element里面查找pad实例,如果查找过程出现问题,则return false(对应name的pad没找到 / pad不是src pad / pad已经有peer pad了,即pad已经被链接过了)。
/* get a src pad */
if (srcpadname) {
/* name specified, look it up */
if (!(srcpad = gst_element_get_static_pad (src, srcpadname))) {
if ((srcpad = gst_element_request_pad_simple (src, srcpadname)))
srcrequest = TRUE;
}
if (!srcpad) {
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no pad %s:%s",
GST_ELEMENT_NAME (src), srcpadname);
return FALSE;
} else {
if (!(GST_PAD_DIRECTION (srcpad) == GST_PAD_SRC)) {
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no src pad",
GST_DEBUG_PAD_NAME (srcpad));
release_and_unref_pad (src, srcpad, srcrequest);
return FALSE;
}
if (GST_PAD_PEER (srcpad) != NULL) {
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
"pad %s:%s is already linked to %s:%s", GST_DEBUG_PAD_NAME (srcpad),
GST_DEBUG_PAD_NAME (GST_PAD_PEER (srcpad)));
/* already linked request pads look like static pads, so the request pad
* was never requested a second time above, so no need to release it */
gst_object_unref (srcpad);
return FALSE;
}
}
srcpads = NULL;
}
如果没有指定上有element的padname
从上游element中找到所有pad,即padlist。
else {
/* no name given, get the first available pad */
GST_OBJECT_LOCK (src);
srcpads = GST_ELEMENT_PADS (src);
srcpad = srcpads ? GST_PAD_CAST (srcpads->data) : NULL;
if (srcpad)
gst_object_ref (srcpad);
GST_OBJECT_UNLOCK (src);
}
注意,这里用的是 GST_ELEMENT_PADS (src) ,是直接吧当前 element 转换为 GstElement,然后获取GstElement的 pads 成员。记住 这里是 “获取 GstElement 的pads 成员”。到这里我想大家应该已经猜出来pad的继承关系了,如果还没懂,我们回忆一下自定义Element如何给自己添加pad。
在instance结构体里定义两个pad成员。
typedef struct _GstMyFilter {
GstElement element;
//pads
GstPad* srcpad; //src pad
GstPad* sinkpad; //sink pad
} GstMyFilter;
在init函数里实例化pad,并且append 到 其 parent element GstElement 的 pads 列表中。
static void gst_my_filter_init(GstMyFilter *filter)
{
...
//instantiates and assigns pads
filter->srcpad = gst_pad_new_from_static_template(&src_factory,"src");
filter->sinkpad = gst_pad_new_from_static_template(&sink_factory, "sink");
//add pads to element
gst_element_add_pad(GST_ELEMENT(filter),filter->srcpad);
gst_element_add_pad(GST_ELEMENT(filter), filter->sinkpad);
...
}
结论
至此,结合上下文,我们已经可以知道 pad 是如何在继承体系中存在的了。
pad仅仅由GstElement使用,所有继承自GstElement 的 element 仅仅是为 GstElement 提供了自定义的 pad实例,同时参与 pad的生命周期管理(fixme if wrong)。
所以,即便 自定义 element 不创建自己的 pad,那么只要其 继承树里某个父类 element 在 init 函数里通过 add pad 函数向 根节点 GstElement里添加过 pad ,那么这个pad就会作为总代理。
773

被折叠的 条评论
为什么被折叠?



