[GStreamer] gst_element_link 及 pad 在继承体系中如何存在

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

前言:

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就会作为总代理。

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值