gstreamer 中link步骤

最近在看gstreamer中的link,下面是应用代码中的一段:

if (gst_element_link_many(data.source, data.h264parse, data.omx264dec, data.convert, data.sink, nullptr) != TRUE) {
    g_printerr("Elements could not be linked.\n");
    gst_object_unref(data.pipeline);
    return -1;
  }

我们来看看都做了些什么:

gboolean
gst_element_link_many (GstElement * element_1, GstElement * element_2, ...)
{
  gboolean res = TRUE;
  va_list args;

  g_return_val_if_fail (GST_IS_ELEMENT (element_1), FALSE);
  g_return_val_if_fail (GST_IS_ELEMENT (element_2), FALSE);

  va_start (args, element_2);
//在这里循环link,按顺序进行的喔
  while (element_2) {
    if (!gst_element_link (element_1, element_2)) {
      res = FALSE;
      break;
    }

    element_1 = element_2;
    element_2 = va_arg (args, GstElement *);
  }

  va_end (args);

  return res;
}

gboolean
gst_element_link (GstElement * src, GstElement * dest)
{
//这里都是匿名pad,自动来连接
  return gst_element_link_pads (src, NULL, dest, NULL);
}

gboolean
gst_element_link_pads (GstElement * src, const gchar * srcpadname,
    GstElement * dest, const gchar * destpadname)
{
//按照默认的方式来link
  return gst_element_link_pads_full (src, srcpadname, dest, destpadname,
      GST_PAD_LINK_CHECK_DEFAULT);
}

层层调用这么多,终于到了link的地方:

gst_element_link_pads_full (src, srcpadname, dest, destpadname,GST_PAD_LINK_CHECK_DEFAULT);

1、获取src ement的srcpad的链表

    srcpads = GST_ELEMENT_PADS (src);
    //获取链表数据指针
    srcpad = srcpads ? GST_PAD_CAST (srcpads->data) : NULL;

2、获取dst element的sinkpad的链表

 destpads = GST_ELEMENT_PADS (dest);
 destpad = destpads ? GST_PAD_CAST (destpads->data) : NULL;

3、首先尝试步骤1中获取到的srcpad链表,看看在其dst-element中有没有匹配的sinkpad

 temp = gst_element_get_compatible_pad (dest, srcpad, NULL);

4、开始link

pad_link_maybe_ghosting (srcpad, temp, flags)

5、返回

return TRUE;

下面详细介绍步骤4中的函数步骤:pad_link_maybe_ghosting (srcpad, temp, flags)

1、首先检查是不是ghosting pad,如果两个pad在同一个bin,说明不用ghosting.

prepare_link_maybe_ghosting (&src, &sink, &pads_created)

2、开始full-link

gst_pad_link_full (src, sink, flags) 

3、继续进入到link_full函数中,首先发送一个GST_STRUCTURE_CHANGE_TYPE_PAD_LINK消息到总线

 gst_element_post_message (parent,
          gst_message_new_structure_change (GST_OBJECT_CAST (sinkpad),
              GST_STRUCTURE_CHANGE_TYPE_PAD_LINK, parent, TRUE));

4、link前的准备工作

 result = gst_pad_link_prepare (srcpad, sinkpad, flags);
 
 //准备工作主要做两件事情
 // 1、 /* check hierarchy, pads can only be linked if the grandparents
   * are the same. */
  if ((flags & GST_PAD_LINK_CHECK_HIERARCHY)
      && !gst_pad_link_check_hierarchy (srcpad, sinkpad))
    goto wrong_hierarchy;

 // 2、 /* check pad caps for non-empty intersection */
 //主要进行下面的工作
 // srccaps = gst_pad_query_caps (src, NULL);
 // sinkcaps = gst_pad_query_caps (sink, NULL);
 // compatible = gst_caps_can_intersect (srccaps, sinkcaps);
  if (!gst_pad_link_check_compatible_unlocked (srcpad, sinkpad, flags))
    goto no_format;

5、开始link,起始非常简单,就是peerpad设置为对方

 /* must set peers before calling the link function */
  GST_PAD_PEER (srcpad) = sinkpad;
  GST_PAD_PEER (sinkpad) = srcpad;

6、协商事件

  /* check events, when something is different, mark pending */
  schedule_events (srcpad, sinkpad);

7、调用linkfunc

 /* get the link functions */
  srcfunc = GST_PAD_LINKFUNC (srcpad);
  sinkfunc = GST_PAD_LINKFUNC (sinkpad);

  if (G_UNLIKELY (srcfunc || sinkfunc)) {
    /* custom link functions, execute them */
    GST_OBJECT_UNLOCK (sinkpad);
    GST_OBJECT_UNLOCK (srcpad);

    if (srcfunc) {
      GstObject *tmpparent;

      ACQUIRE_PARENT (srcpad, tmpparent, no_parent);
      /* this one will call the peer link function */
      result = srcfunc (srcpad, tmpparent, sinkpad);
      RELEASE_PARENT (tmpparent);
    } else if (sinkfunc) {
      GstObject *tmpparent;

      ACQUIRE_PARENT (sinkpad, tmpparent, no_parent);
      /* if no source link function, we need to call the sink link
       * function ourselves. */
      result = sinkfunc (sinkpad, tmpparent, srcpad);
      RELEASE_PARENT (tmpparent);
    }

8、发送信号

  /* fire off a signal to each of the pads telling them
   * that they've been linked */
  g_signal_emit (srcpad, gst_pad_signals[PAD_LINKED], 0, sinkpad);
  g_signal_emit (sinkpad, gst_pad_signals[PAD_LINKED], 0, srcpad);

9、发送reconfigure事件

 if (!(flags & GST_PAD_LINK_CHECK_NO_RECONFIGURE))
    gst_pad_send_event (srcpad, gst_event_new_reconfigure ());

10、再次发送msg

  gst_element_post_message (parent,
        gst_message_new_structure_change (GST_OBJECT_CAST (sinkpad),
            GST_STRUCTURE_CHANGE_TYPE_PAD_LINK, parent, FALSE));

下面看看

schedule_events (GstPad * srcpad, GstPad * sinkpad)
``
主要看srcpad上的event和dstpad上的event,如果有不相同的,则把srcpad上的事件标记为received=%FALSE,下次就可以发送
```c
/* check all events on srcpad against those on sinkpad. All events that are not
 * on sinkpad are marked as received=%FALSE and the PENDING_EVENTS is set on the
 * srcpad so that the events will be sent next time */
/* should be called with srcpad and sinkpad LOCKS */
static void
schedule_events (GstPad * srcpad, GstPad * sinkpad)
{
  gint i, len;
  GArray *events;
  PadEvent *ev;
  gboolean pending = FALSE;

//获取到srcpad的events链表
  events = srcpad->priv->events;
  len = events->len;

  for (i = 0; i < len; i++) {
    ev = &g_array_index (events, PadEvent, i);
    if (ev->event == NULL)
      continue;
//其实就是两个for循环遍历对比srcpad和sinkpad中evens是否相等
    if (sinkpad == NULL || !find_event (sinkpad, ev->event)) {
      ev->received = FALSE;
      pending = TRUE;
    }
  }
  if (pending)
    GST_OBJECT_FLAG_SET (srcpad, GST_PAD_FLAG_PENDING_EVENTS);
}


/* should be called with OBJECT lock */
static PadEvent *
find_event (GstPad * pad, GstEvent * event)
{
  guint i, len;
  GArray *events;
  PadEvent *ev;

  events = pad->priv->events;
  len = events->len;

  for (i = 0; i < len; i++) {
    ev = &g_array_index (events, PadEvent, i);
    if (event == ev->event)
      goto found;
    else if (GST_EVENT_TYPE (ev->event) > GST_EVENT_TYPE (event))
      break;
  }
  ev = NULL;
found:
  return ev;
}

纵观上面,
上面牵扯到两个非常重要的函数
gst_element_get_compatible_pad()函数定义如下:

//上面对caps传入了null,element出入了dstpad,这个好理解,为srcpad找一个dstpad
GstPad *
gst_element_get_compatible_pad (GstElement * element, GstPad * pad,
    GstCaps * caps)
{
  GstIterator *pads;
  GstPadTemplate *templ;
  GstCaps *templcaps;
  GstPad *foundpad = NULL;
  gboolean done;
  GValue padptr = { 0, };

  g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
  g_return_val_if_fail (GST_IS_PAD (pad), NULL);

//日志:
//finding pad in h264-parse compatible with app-source:src
  GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
      "finding pad in %s compatible with %s:%s",
      GST_ELEMENT_NAME (element), GST_DEBUG_PAD_NAME (pad));

  g_return_val_if_fail (GST_PAD_PEER (pad) == NULL, NULL);

  done = FALSE;

  /* try to get an existing unlinked pad */
  //从dst中的sinkpad中获取迭代器
  if (GST_PAD_IS_SRC (pad)) {
    pads = gst_element_iterate_sink_pads (element);
  } else if (GST_PAD_IS_SINK (pad)) {
    pads = gst_element_iterate_src_pads (element);
  } else {
    pads = gst_element_iterate_pads (element);
  }

  while (!done) {
    switch (gst_iterator_next (pads, &padptr)) {
      case GST_ITERATOR_OK:
      {
        GstPad *peer;
        GstPad *current;
        GstPad *srcpad;
        GstPad *sinkpad;

        current = g_value_get_object (&padptr);
		//日志:
		// examining pad h264-parse:sink
        GST_CAT_LOG (GST_CAT_ELEMENT_PADS, "examining pad %s:%s",
            GST_DEBUG_PAD_NAME (current));

        if (GST_PAD_IS_SRC (current)) {
          srcpad = current;
          sinkpad = pad;
        } else {
          srcpad = pad;
          sinkpad = current;
        }
        //获取peer pad保证为null,因为link的时候必须peer pad 是为NULL的
        peer = gst_pad_get_peer (current);
		//检查能不能link
        if (peer == NULL && gst_pad_check_link (srcpad, sinkpad)) {
          GstCaps *temp, *intersection;
          gboolean compatible;

          /* Now check if the two pads' caps are compatible */
          temp = gst_pad_query_caps (pad, NULL);
          if (caps) {
            intersection = gst_caps_intersect (temp, caps);
            gst_caps_unref (temp);
          } else {
          //因为caps为null
            intersection = temp;
          }

          temp = gst_pad_query_caps (current, NULL);
          //是怎么做交集的呢
          compatible = gst_caps_can_intersect (temp, intersection);
          gst_caps_unref (temp);
          gst_caps_unref (intersection);

          if (compatible) {
            GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
                "found existing unlinked compatible pad %s:%s",
                GST_DEBUG_PAD_NAME (current));
            gst_iterator_free (pads);

            current = gst_object_ref (current);
            g_value_unset (&padptr);
			//说明有存在的pad 可以link
            return current;
          } else {
            GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "incompatible pads");
          }
        } else {
          GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
              "already linked or cannot be linked (peer = %p)", peer);
        }
        GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "unreffing pads");

        g_value_reset (&padptr);
        if (peer)
          gst_object_unref (peer);
        break;
      }
  ...
    }
  }//while
  g_value_unset (&padptr);
  gst_iterator_free (pads);
...

上面用到了 compatible = gst_caps_can_intersect (temp, intersection);,那么具体操作是

boolean
gst_caps_can_intersect (const GstCaps * caps1, const GstCaps * caps2)
{
  guint64 i;                    /* index can be up to 2 * G_MAX_UINT */
  guint j, k, len1, len2;
  GstStructure *struct1;
  GstStructure *struct2;
  GstCapsFeatures *features1;
  GstCapsFeatures *features2;

  g_return_val_if_fail (GST_IS_CAPS (caps1), FALSE);
  g_return_val_if_fail (GST_IS_CAPS (caps2), FALSE);

  /* caps are exactly the same pointers */
  if (G_UNLIKELY (caps1 == caps2))
    return TRUE;

  /* empty caps on either side, return empty */
  if (G_UNLIKELY (CAPS_IS_EMPTY (caps1) || CAPS_IS_EMPTY (caps2)))
    return FALSE;

  /* one of the caps is any */
  if (G_UNLIKELY (CAPS_IS_ANY (caps1) || CAPS_IS_ANY (caps2)))
    return TRUE;

  /* run zigzag on top line then right line, this preserves the caps order
   * much better than a simple loop.
   *
   * This algorithm zigzags over the caps structures as demonstrated in
   * the following matrix:
   *
   *          caps1                              0  1  2  3
   *       +-------------     total distance:  +-------------
   *       | 1  2  4  7                      0 | 0  1  2  3
   * caps2 | 3  5  8 10                      1 | 1  2  3  4
   *       | 6  9 11 12                      2 | 2  3  4  5
   *
   * First we iterate over the caps1 structures (top line) intersecting
   * the structures diagonally down, then we iterate over the caps2
   * structures. The result is that the intersections are ordered based on the
   * sum of the indexes in the list.
   */
  len1 = GST_CAPS_LEN (caps1);
  len2 = GST_CAPS_LEN (caps2);
  for (i = 0; i < len1 + len2 - 1; i++) {
    /* superset index goes from 0 to superset->structs->len-1 */
    j = MIN (i, len1 - 1);
    /* subset index stays 0 until i reaches superset->structs->len, then it
     * counts up from 1 to subset->structs->len - 1 */
    k = (i > j) ? (i - j) : 0;  /* MAX (0, i - j) */
    /* now run the diagonal line, end condition is the left or bottom
     * border */
    while (k < len2) {
      struct1 = gst_caps_get_structure_unchecked (caps1, j);
      features1 = gst_caps_get_features_unchecked (caps1, j);
      if (!features1)
        features1 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
      struct2 = gst_caps_get_structure_unchecked (caps2, k);
      features2 = gst_caps_get_features_unchecked (caps2, k);
      if (!features2)
        features2 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
      if (gst_caps_features_is_equal (features1, features2) &&
          gst_structure_can_intersect (struct1, struct2)) {
        return TRUE;
      }
      /* move down left */
      k++;
      if (G_UNLIKELY (j == 0))
        break;                  /* so we don't roll back to G_MAXUINT */
      j--;
    }
  }

  return FALSE;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值