【GStreamer】GstPad的简单分析

模块的简单分析
【GStreamer】GstAllocator的简单分析
【GStreamer】GstMemory的简单分析
【GStreamer】GstBuffer的简单分析
【GStreamer】GstPad的简单分析
【GStreamer】GstElement的简单分析
【GStreamer】GstBus和GstMessage的简单分析
【GStreamer】GstDevice和GstPlugin的简单分析

GstPad用于在pipeline中连接不同的元素(GstElement),可以将pad理解为一个元素的连接点或者端口,数据通过这些连接点在元素之间流动。pad的核心作用是,数据流动的接口,可以是某一个元素的数据接收端口,也可以是某一个元素的数据发送端口。使用capabilities(Caps)描述pad可以处理的数据类型(如视频、音频、具体的编码格式等),必须确保两个pad的caps可以兼容。

有些pad是静态的(在元素创建时就存在),有些pad是动态的(在运行时根据需要创建),例如decodebin元素会根据输入的媒体类型动态的创建相应的pad。pad除了负责数据传输之外,还可以处理各种时间,例如流开始、流结束、刷新、查询和控制流速

1.pad结构体定义

(1)pad方向的定义

typedef enum {
  GST_PAD_UNKNOWN,
  GST_PAD_SRC,	// 发送数据的pad
  GST_PAD_SINK	// 接收数据的pad
} GstPadDirection;

(2)pad模式的定义,描述pad的工作模式,决定了pad如何处理数据流

typedef enum {
  GST_PAD_MODE_NONE,  // 非活跃状态
  GST_PAD_MODE_PUSH,  // 推流模式
  GST_PAD_MODE_PULL   // 拉流模式
} GstPadMode;

(3)GstPadLinkReturn表示尝试链接两个pad的结果类型

typedef enum {
  // 链接成功
  GST_PAD_LINK_OK               =  0,
  // 两个pad没有共同的祖父元素(必须具有共同的祖父元素才能链接成功)
  GST_PAD_LINK_WRONG_HIERARCHY  = -1,
  // pad已经处于链接状态
  GST_PAD_LINK_WAS_LINKED       = -2,
  // 两个pad的方向不匹配
  GST_PAD_LINK_WRONG_DIRECTION  = -3,
  // 两个pad格式(caps)不兼容
  GST_PAD_LINK_NOFORMAT         = -4,
  // 两个pad无法在调度(scheduling)上协作
  GST_PAD_LINK_NOSCHED          = -5,
  // 拒绝链接,但是需要排查错误
  GST_PAD_LINK_REFUSED          = -6
} GstPadLinkReturn;

(4)GstFlowReturn描述了数据传递的结果

typedef enum {
  /* custom success starts here */
  // 可以自定义成功返回值
  GST_FLOW_CUSTOM_SUCCESS_2 = 102,
  GST_FLOW_CUSTOM_SUCCESS_1 = 101,
  GST_FLOW_CUSTOM_SUCCESS = 100,

  /* core predefined */
  // 数据传递成功
  GST_FLOW_OK		  =  0,
  /* expected failures */
  // pad未连接到其他pad
  // 如果尝试向未连接的pad传递数据,会返回此值
  GST_FLOW_NOT_LINKED     = -1,
  // pad处于刷新状态
  // 刷新状态下,pad不会处理数据,而是丢弃传入的数据
  GST_FLOW_FLUSHING       = -2,
  /* error cases */
  // 数据流结束
  GST_FLOW_EOS            = -3,
  // pad格式(caps)未协商成功
  GST_FLOW_NOT_NEGOTIATED = -4,
  // 发生错误
  // 生成错误的元素可以使用GST_ELEMENT_ERROR()发布错误信息
  GST_FLOW_ERROR	  = -5,
  // 当前操作不支持
  GST_FLOW_NOT_SUPPORTED  = -6,

  /* custom error starts here */
  // 自定义错误代码
  GST_FLOW_CUSTOM_ERROR   = -100,
  GST_FLOW_CUSTOM_ERROR_1 = -101,
  GST_FLOW_CUSTOM_ERROR_2 = -102
} GstFlowReturn;

(5)GstPadLinkCheck控制在连接两个pad时,需要执行哪些检查的枚举类型,定义了在pad连接过程中可以启用的各种检查选项,以确保连接的合法性和安全性

typedef enum {
  // 不进行任何检查
  GST_PAD_LINK_CHECK_NOTHING       = 0,
  // 检查两个pad是否具有相同的父元素或者祖父元素
  GST_PAD_LINK_CHECK_HIERARCHY     = 1 << 0,
  // 使用pad的模板caps检查它们的兼容性
  GST_PAD_LINK_CHECK_TEMPLATE_CAPS = 1 << 1,
  // 使用gst_pad_query_caps()返回的caps检查pad的兼容性
  // 这种检查更安全,但性能开销较大
  GST_PAD_LINK_CHECK_CAPS          = 1 << 2,


  /* Not really checks, more like flags
 - Added here to avoid creating a new gst_pad_link_variant */
  // 不允许在连接pad时,重新配置事件
  GST_PAD_LINK_CHECK_NO_RECONFIGURE = 1 << 3,
  // 默认检查选项
  GST_PAD_LINK_CHECK_DEFAULT       = GST_PAD_LINK_CHECK_HIERARCHY | GST_PAD_LINK_CHECK_CAPS
} GstPadLinkCheck;

(6)GstPadProbeType描述了pad探针(probe)类型的枚举类型,探针允许开发者在数据流经pad时插入回调函数,以监控或者修改数据

typedef enum
{
  // 无效的探针类型
  GST_PAD_PROBE_TYPE_INVALID          = 0,
  /* flags to control blocking */
  // 监控空闲pad,并在回调函数调用时阻塞pad
  GST_PAD_PROBE_TYPE_IDLE             = (1 << 0),
  // 监控并阻塞pad
  GST_PAD_PROBE_TYPE_BLOCK            = (1 << 1),
  /* flags to select datatypes */
  // 监控缓冲区buffer
  GST_PAD_PROBE_TYPE_BUFFER           = (1 << 4),
  // 监控缓冲区列表buffer list
  GST_PAD_PROBE_TYPE_BUFFER_LIST      = (1 << 5),
  // 监控下游事件(如EOS、Segment)
  GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM = (1 << 6),
  // 监控上游事件(如FLUSH_START、FLUSH_STOP等)
  GST_PAD_PROBE_TYPE_EVENT_UPSTREAM   = (1 << 7),
  // 监控刷新事件(FLUSH)
  // 需要显式调用,不包含在EVENT_DOWNSTREAM和EVENT_UPSTREAM中
  GST_PAD_PROBE_TYPE_EVENT_FLUSH      = (1 << 8),
  // 监控下游查询(如DURATION、POSITION等)
  GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM = (1 << 9),
  // 监控上游查询
  GST_PAD_PROBE_TYPE_QUERY_UPSTREAM   = (1 << 10),
  /* flags to select scheduling mode */
  // 监控推流模式的数据流
  GST_PAD_PROBE_TYPE_PUSH             = (1 << 12),
  // 监控拉流模式的数据流
  GST_PAD_PROBE_TYPE_PULL             = (1 << 13),

  /* flag combinations */
  // 组合模式
  GST_PAD_PROBE_TYPE_BLOCKING         = GST_PAD_PROBE_TYPE_IDLE | GST_PAD_PROBE_TYPE_BLOCK,
  GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM  = GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
  GST_PAD_PROBE_TYPE_DATA_UPSTREAM    = GST_PAD_PROBE_TYPE_EVENT_UPSTREAM,
  GST_PAD_PROBE_TYPE_DATA_BOTH        = GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM | GST_PAD_PROBE_TYPE_DATA_UPSTREAM,
  GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM = GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
  GST_PAD_PROBE_TYPE_BLOCK_UPSTREAM   = GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_DATA_UPSTREAM,
  GST_PAD_PROBE_TYPE_EVENT_BOTH       = GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM | GST_PAD_PROBE_TYPE_EVENT_UPSTREAM,
  GST_PAD_PROBE_TYPE_QUERY_BOTH       = GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM | GST_PAD_PROBE_TYPE_QUERY_UPSTREAM,
  GST_PAD_PROBE_TYPE_ALL_BOTH         = GST_PAD_PROBE_TYPE_DATA_BOTH | GST_PAD_PROBE_TYPE_QUERY_BOTH,
  GST_PAD_PROBE_TYPE_SCHEDULING       = GST_PAD_PROBE_TYPE_PUSH | GST_PAD_PROBE_TYPE_PULL
} GstPadProbeType;

(7)GstPadProbeReturn描述了pad探针回调函数返回值的枚举类型,决定了探针如何处理流经pad的数据(如缓冲区、事件、查询等),并控制数据是否继续传递、是否丢弃、是否移除探针等行为

typedef enum
{
  // 丢弃数据
  GST_PAD_PROBE_DROP,
  // 正常返回值,探针保持激活状态
  GST_PAD_PROBE_OK,
  // 移除当前探针,并允许数据继续传递
  GST_PAD_PROBE_REMOVE,
  // 允许当前数据项通过,并在下一个数据项上继续阻塞
  GST_PAD_PROBE_PASS,
  // 数据已在探针中被处理,不会继续传递
  GST_PAD_PROBE_HANDLED
} GstPadProbeReturn;

(8)GstPadFlags描述pad状态和行为的标志枚举类型,用于指示pad的当前状态、配置需求以及如何处理事件和查询。每个标志位都代表pad的某种特定状态或行为

typedef enum {
  // 数据流被阻塞
  GST_PAD_FLAG_BLOCKED          = (GST_OBJECT_FLAG_LAST << 0),
  // 正在刷新
  GST_PAD_FLAG_FLUSHING         = (GST_OBJECT_FLAG_LAST << 1),
  // 到达流末尾
  GST_PAD_FLAG_EOS              = (GST_OBJECT_FLAG_LAST << 2),
  // 正在阻塞某个缓冲区或者事件
  GST_PAD_FLAG_BLOCKING         = (GST_OBJECT_FLAG_LAST << 3),
  // 需要确保存在父对象才能调用pad的回调函数
  GST_PAD_FLAG_NEED_PARENT      = (GST_OBJECT_FLAG_LAST << 4),
  // 需要重新配置或重新协商(需要手动清除)
  GST_PAD_FLAG_NEED_RECONFIGURE = (GST_OBJECT_FLAG_LAST << 5),
  // 有待处理的事件
  GST_PAD_FLAG_PENDING_EVENTS   = (GST_OBJECT_FLAG_LAST << 6),
  // 使用固定的caps
  GST_PAD_FLAG_FIXED_CAPS       = (GST_OBJECT_FLAG_LAST << 7),
  // 默认事件和查询处理程序会将所有事件和查询转发到内部链接的pad
  GST_PAD_FLAG_PROXY_CAPS       = (GST_OBJECT_FLAG_LAST << 8),
  // 默认处理程序会将分配查询(Allocation Query)转发到内部pad
  GST_PAD_FLAG_PROXY_ALLOCATION = (GST_OBJECT_FLAG_LAST << 9),
  // 默认处理程序会将调度查询(Scheduling Query)转发到内部pad
  GST_PAD_FLAG_PROXY_SCHEDULING = (GST_OBJECT_FLAG_LAST << 10),
  // 默认accept-caps处理程序会检查caps是否与查询结果相交
  GST_PAD_FLAG_ACCEPT_INTERSECT = (GST_OBJECT_FLAG_LAST << 11),
  // 默认accept-caps处理程序会使用模板pad的caps而不是查询caps来进行比较
  GST_PAD_FLAG_ACCEPT_TEMPLATE  = (GST_OBJECT_FLAG_LAST << 12),
  /* padding */
  GST_PAD_FLAG_LAST        = (GST_OBJECT_FLAG_LAST << 16)
} GstPadFlags;

(9)GstPad中包含了pad的各种属性和功能函数,用于管理数据流、事件处理、查询处理等

struct _GstPad {
  GstObject                      object;

  /*< public >*/
  // 父元素的私有数据
  gpointer                       element_private;
  // padtemplate中定义了pad的静态属性,例如方向、支持的Caps等
  GstPadTemplate                *padtemplate;
  // pad的方向(SRC或SINK),创建之后不可修改
  GstPadDirection                direction;

  /*< private >*/
  /* streaming rec_lock */
  // 保护pad数据流的递归互斥锁,确保在多线程环境下对pad数据流的访问是线程安全地
  GRecMutex		         stream_rec_lock;
  // task管理pad的数据流处理任务
  GstTask			*task;

  /* block cond, mutex is from the object */
  // 条件变量,用于在pad阻塞时等待条件满足
  GCond				 block_cond;
  // 探针列表,用于监控和拦截数据流
  GHookList                      probes;
  // pad的当前模式(PUSH、PULL)
  GstPadMode		         mode;
  // 激活函数
  GstPadActivateFunction	 activatefunc;
  gpointer                       activatedata;
  GDestroyNotify                 activatenotify;
  // 激活模式函数
  GstPadActivateModeFunction	 activatemodefunc;
  gpointer                       activatemodedata;
  GDestroyNotify                 activatemodenotify;

  /* pad link */
  // 当前pad的对端pad
  GstPad			*peer;
  // 链接函数
  GstPadLinkFunction		 linkfunc;
  gpointer                       linkdata;
  GDestroyNotify                 linknotify;
  // 断开链接函数
  GstPadUnlinkFunction		 unlinkfunc;
  gpointer                       unlinkdata;
  GDestroyNotify                 unlinknotify;

  /* data transport functions */
  // 数据链函数,处理数据时调用
  GstPadChainFunction		 chainfunc;
  // 用户数据
  gpointer                       chaindata;
  GDestroyNotify                 chainnotify;
  // 数据链列表函数,用于处理多个数据缓冲区
  GstPadChainListFunction        chainlistfunc;
  gpointer                       chainlistdata;
  GDestroyNotify                 chainlistnotify;
  // 在PULL模式下,获取数据范围
  GstPadGetRangeFunction	 getrangefunc;
  gpointer                       getrangedata;
  GDestroyNotify                 getrangenotify;
  // 处理流事件(如EOS、SEGMENT等)
  GstPadEventFunction		 eventfunc;
  gpointer                       eventdata;
  GDestroyNotify                 eventnotify;

  /* pad offset */
  // 偏移量,用于跟踪数据流的位置
  gint64                         offset;

  /* generic query method */
  // 用于处理查询请求(如定位、持续事件等)
  GstPadQueryFunction		 queryfunc;
  gpointer                       querydata;
  GDestroyNotify                 querynotify;

  /* internal links */
  // 内部链接迭代函数,遍历内部链接
  GstPadIterIntLinkFunction      iterintlinkfunc;
  gpointer                       iterintlinkdata;
  GDestroyNotify                 iterintlinknotify;

  /* counts number of probes attached. */
  // 附加到pad的探针数量
  gint				 num_probes;
  // 当前被阻塞的探针数量
  gint				 num_blocked;
  // pad的私有数据
  GstPadPrivate                 *priv;

  union {
    gpointer _gst_reserved[GST_PADDING];
    struct {
      GstFlowReturn last_flowret;
      GstPadEventFullFunction eventfullfunc;
    } abi;
  } ABI;
};

_GstPadClass是GstPad的父类,其中包含了链接函数和断开链接函数

struct _GstPadClass {
  GstObjectClass	parent_class;

  /* signal callbacks */
  void		(*linked)		(GstPad *pad, GstPad *peer);
  void		(*unlinked)		(GstPad *pad, GstPad *peer);

  /*< private >*/
  gpointer _gst_reserved[GST_PADDING];
};

2.主要函数

2.1 初始化

(1)gst_pad_class_init
_GstPadClass的初始化,设置pad的虚函数(dispose、finalize),注册pad的信号(linked,unlinked),定义pad的属性(caps、direction和template)

static void
gst_pad_class_init (GstPadClass * klass)
{
  GObjectClass *gobject_class;
  GstObjectClass *gstobject_class;

  gobject_class = G_OBJECT_CLASS (klass);
  gstobject_class = GST_OBJECT_CLASS (klass);
  // dispose在对象销毁时被调用,用于释放资源
  gobject_class->dispose = gst_pad_dispose;
  // finalize在对象被完全释放时调用,用于清理内存
  gobject_class->finalize = gst_pad_finalize;
  // 设置对象属性
  gobject_class->set_property = gst_pad_set_property;
  // 获取对象属性
  gobject_class->get_property = gst_pad_get_property;

  /**
 - GstPad::linked:
 - @pad: the pad that emitted the signal
 - @peer: the peer pad that has been connected
 -  6. Signals that a pad has been linked to the peer pad.
   */
  // 定义PAD_LINKED信号,当pad与另一个pad链接时触发
  // "linked":信号名称
  // G_TYPE_FROM_CLASS(kclass):信号所属类型,这里是GstPadClass
  // G_SIGNAL_RUN_LAST:信号的运行方式,这里表示信号的默认处理函数将在所有连接的信号处理器之后运行
  // G_STRUCT_OFFSET(GstPadClass, linked):指定信号的默认处理函数在类结构体中的偏移量
  // 前两个NULL:信号的累加器函数和累加器数据,这里表示不使用累加器
  // 第三个NULL:回调函数
  // G_TYPE_NONE:信号的返回类型,这里表示没有返回值
  // 1: 信号的参数数量,这里只有1个
  // GST_TYPE_PAD: 信号的参数类型,表示信号的第一个参数是GstPad类型
  // 这里最关键的地方,是当发生连接时,调用的是linked()这个函数,这是一个GstPadClass中的成员
  gst_pad_signals[PAD_LINKED] =
      g_signal_new ("linked", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
      G_STRUCT_OFFSET (GstPadClass, linked), NULL, NULL,
      NULL, G_TYPE_NONE, 1, GST_TYPE_PAD);
  /**
 - GstPad::unlinked:
 - @pad: the pad that emitted the signal
 - @peer: the peer pad that has been disconnected
 -  11. Signals that a pad has been unlinked from the peer pad.
   */
  // 定义PAD_UNLINKED信号,当pad与另一个pad断开连接时触发
  gst_pad_signals[PAD_UNLINKED] =
      g_signal_new ("unlinked", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
      G_STRUCT_OFFSET (GstPadClass, unlinked), NULL, NULL,
      NULL, G_TYPE_NONE, 1, GST_TYPE_PAD);
  // 定义属性caps
  pspec_caps = g_param_spec_boxed ("caps", "Caps",
      "The capabilities of the pad", GST_TYPE_CAPS,
      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
  // 将caps属性install到pad类中
  g_object_class_install_property (gobject_class, PAD_PROP_CAPS, pspec_caps);
  // 将direction属性install到pad类中
  g_object_class_install_property (gobject_class, PAD_PROP_DIRECTION,
      g_param_spec_enum ("direction", "Direction", "The direction of the pad",
          GST_TYPE_PAD_DIRECTION, GST_PAD_UNKNOWN,
          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));

  /* FIXME, Make G_PARAM_CONSTRUCT_ONLY when we fix ghostpads. */
  // 将template属性install到pad类中
  g_object_class_install_property (gobject_class, PAD_PROP_TEMPLATE,
      g_param_spec_object ("template", "Template",
          "The GstPadTemplate of this pad", GST_TYPE_PAD_TEMPLATE,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

  /**
 - GstPad:offset:
 -  14. The offset that will be applied to the running time of the pad.
 -  16. Since: 1.6
   */
  // 将offset属性install到pad类中
  g_object_class_install_property (gobject_class, PAD_PROP_OFFSET,
      g_param_spec_int64 ("offset", "Offset",
          "The running time offset of the pad", 0, G_MAXINT64, 0,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  // 设置pad的路径分隔符为.
  gstobject_class->path_string_separator = ".";

  /* Register common function pointer descriptions */
  // 注册一些常规的函数,激活函数,事件函数,查询函数等
  // 默认的激活函数,在没有定义激活函数时才使用,一般不用
  GST_DEBUG_REGISTER_FUNCPTR (gst_pad_activate_default);
  GST_DEBUG_REGISTER_FUNCPTR (gst_pad_event_default);
  GST_DEBUG_REGISTER_FUNCPTR (gst_pad_query_default);
  GST_DEBUG_REGISTER_FUNCPTR (gst_pad_iterate_internal_links_default);
  GST_DEBUG_REGISTER_FUNCPTR (gst_pad_chain_list_default);
}

(2)gst_pad_init

static void
gst_pad_init (GstPad * pad)
{
  pad->priv = gst_pad_get_instance_private (pad);

  GST_PAD_DIRECTION (pad) = GST_PAD_UNKNOWN;
  
  GST_PAD_ACTIVATEFUNC (pad) = gst_pad_activate_default;
  GST_PAD_EVENTFUNC (pad) = gst_pad_event_default;
  GST_PAD_QUERYFUNC (pad) = gst_pad_query_default;
  GST_PAD_ITERINTLINKFUNC (pad) = gst_pad_iterate_internal_links_default;
  GST_PAD_CHAINLISTFUNC (pad) = gst_pad_chain_list_default;

  GST_PAD_SET_FLUSHING (pad);

  g_rec_mutex_init (&pad->stream_rec_lock);

  g_cond_init (&pad->block_cond);

  g_hook_list_init (&pad->probes, sizeof (GstProbe));

  pad->priv->events = g_array_sized_new (FALSE, TRUE, sizeof (PadEvent), 16);
  pad->priv->events_cookie = 0;
  pad->priv->last_cookie = -1;
  g_cond_init (&pad->priv->activation_cond);

  pad->ABI.abi.last_flowret = GST_FLOW_FLUSHING;
}

2.2 pad链接(gst_pad_link)

GstPadLinkReturn
gst_pad_link (GstPad * srcpad, GstPad * sinkpad)
{
  return gst_pad_link_full (srcpad, sinkpad, GST_PAD_LINK_CHECK_DEFAULT);
}

gst_pad_link_full()执行链接的具体操作,主要过程为:

1.链接准备(gst_pad_link_prepare)
2.设置对端pad(GST_PAD_PEER)
3.调度事件(schedule_events),为自定义链接做准备,确保不会出现访问冲突
4.自定义链接(srcfunc或sinkfunc),通常不会执行自定义链接,不会进行这个步骤
5.链接完成(g_signal_emit ),发送信号表示两个pad链接成功
其中,pad链接最核心的地方在于设置peer,而不是自定义链接

GstPadLinkReturn
gst_pad_link_full (GstPad * srcpad, GstPad * sinkpad, GstPadLinkCheck flags)
{
  GstPadLinkReturn result;
  GstElement *parent;
  GstPadLinkFunction srcfunc, sinkfunc;

  g_return_val_if_fail (GST_IS_PAD (srcpad), GST_PAD_LINK_REFUSED);
  g_return_val_if_fail (GST_PAD_IS_SRC (srcpad), GST_PAD_LINK_WRONG_DIRECTION);
  g_return_val_if_fail (GST_IS_PAD (sinkpad), GST_PAD_LINK_REFUSED);
  g_return_val_if_fail (GST_PAD_IS_SINK (sinkpad),
      GST_PAD_LINK_WRONG_DIRECTION);

  GST_TRACER_PAD_LINK_PRE (srcpad, sinkpad);

  /* Notify the parent early. See gst_pad_unlink for details. */
  if (G_LIKELY ((parent = GST_ELEMENT_CAST (gst_pad_get_parent (srcpad))))) {
    if (G_LIKELY (GST_IS_ELEMENT (parent))) {
      gst_element_post_message (parent,
          gst_message_new_structure_change (GST_OBJECT_CAST (sinkpad),
              GST_STRUCTURE_CHANGE_TYPE_PAD_LINK, parent, TRUE));
    } else {
      gst_object_unref (parent);
      parent = NULL;
    }
  }

  /* prepare will also lock the two pads */
  // 1.为链接进行准备
  result = gst_pad_link_prepare (srcpad, sinkpad, flags);

  if (G_UNLIKELY (result != GST_PAD_LINK_OK)) {
    GST_CAT_INFO (GST_CAT_PADS, "link between %s:%s and %s:%s failed: %s",
        GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad),
        gst_pad_link_get_name (result));
    goto done;
  }

  /* must set peers before calling the link function */
  // 2.设置两个pad的对端pad,实际上这就是链接的核心,后续的链接函数是用户自定义的,
  // 可以执行一些用户期望的操作,但不影响链接
  GST_PAD_PEER (srcpad) = sinkpad;
  GST_PAD_PEER (sinkpad) = srcpad;

  /* check events, when something is different, mark pending */
  // 3.调度事件,
  schedule_events (srcpad, sinkpad);

  /* get the link functions */
  srcfunc = GST_PAD_LINKFUNC (srcpad);
  sinkfunc = GST_PAD_LINKFUNC (sinkpad);
  // 4.G_UNLIKELY表示srcfunc或sinkfunc通常不太会被定义
  // 通常情况下,不会自定义链接函数
  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);
    }
  no_parent:

    GST_OBJECT_LOCK (srcpad);
    GST_OBJECT_LOCK (sinkpad);

    /* we released the lock, check if the same pads are linked still */
    if (GST_PAD_PEER (srcpad) != sinkpad || GST_PAD_PEER (sinkpad) != srcpad)
      goto concurrent_link;

    if (G_UNLIKELY (result != GST_PAD_LINK_OK))
      goto link_failed;
  }
  GST_OBJECT_UNLOCK (sinkpad);
  GST_OBJECT_UNLOCK (srcpad);

  /* fire off a signal to each of the pads telling them
   * that they've been linked */
  // 5.发送信号,表明两个pad已经链接成功
  g_signal_emit (srcpad, gst_pad_signals[PAD_LINKED], 0, sinkpad);
  g_signal_emit (sinkpad, gst_pad_signals[PAD_LINKED], 0, srcpad);

  GST_CAT_INFO (GST_CAT_PADS, "linked %s:%s and %s:%s, successful",
      GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));

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

done:
  if (G_LIKELY (parent)) {
    gst_element_post_message (parent,
        gst_message_new_structure_change (GST_OBJECT_CAST (sinkpad),
            GST_STRUCTURE_CHANGE_TYPE_PAD_LINK, parent, FALSE));
    gst_object_unref (parent);
  }

  GST_TRACER_PAD_LINK_POST (srcpad, sinkpad, result);
  return result;

  /* ERRORS */
concurrent_link:
  {
    GST_CAT_INFO (GST_CAT_PADS, "concurrent link between %s:%s and %s:%s",
        GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
    GST_OBJECT_UNLOCK (sinkpad);
    GST_OBJECT_UNLOCK (srcpad);

    /* The other link operation succeeded first */
    result = GST_PAD_LINK_WAS_LINKED;
    goto done;
  }
link_failed:
  {
    GST_CAT_INFO (GST_CAT_PADS, "link between %s:%s and %s:%s failed: %s",
        GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad),
        gst_pad_link_get_name (result));

    GST_PAD_PEER (srcpad) = NULL;
    GST_PAD_PEER (sinkpad) = NULL;

    GST_OBJECT_UNLOCK (sinkpad);
    GST_OBJECT_UNLOCK (srcpad);

    goto done;
  }
}

(1)gst_pad_link_prepare
为链接过程做准备,检查两个pad的状态、媒体类型和调度模式是否兼容,确保可以安全地链接

static GstPadLinkReturn
gst_pad_link_prepare (GstPad * srcpad, GstPad * sinkpad, GstPadLinkCheck flags)
{
  GstPadLinkReturn result;

  GST_CAT_INFO (GST_CAT_PADS, "trying to link %s:%s and %s:%s",
      GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));

  GST_OBJECT_LOCK (srcpad);
  GST_OBJECT_LOCK (sinkpad);

  /* Check pads state, not already linked and correct hierachy. */
  // 检查srcpad和sinkpad是否已链接,并检查是否具有相同的父辈
  // 只有具有相同的父辈,才可以执行链接过程
  result = gst_pad_link_check_relations (srcpad, sinkpad, flags);
  if (result != GST_PAD_LINK_OK)
    goto unlock_and_return;

  /* check pad caps for non-empty intersection */
  // 检查srcpad和sinkpad的媒体类型(caps)是否兼容
  if (!gst_pad_link_check_compatible_unlocked (srcpad, sinkpad, flags)) {
    GST_CAT_INFO (GST_CAT_PADS, "caps are incompatible");
    result = GST_PAD_LINK_NOFORMAT;
    goto unlock_and_return;
  }

  /* Need to recheck our pads since gst_pad_link_check_compatible_unlocked might have temporarily unlocked them.
     Keeping the first check, because gst_pad_link_check_compatible_unlocked potentially is an expensive operation
     which gst_pad_link_check_relations is not. */
  /* 重新检查relation的原因是gst_pad_link_check_compatible_unlocked可能会临时解锁pad,
   * 导致其他线程可能修改pad状态,重新检查以确保仍符合链接要求
   */
  result = gst_pad_link_check_relations (srcpad, sinkpad, flags);
  if (result != GST_PAD_LINK_OK)
    goto unlock_and_return;

  /* FIXME check pad scheduling for non-empty intersection */

  return GST_PAD_LINK_OK;

unlock_and_return:
  {
    GST_OBJECT_UNLOCK (sinkpad);
    GST_OBJECT_UNLOCK (srcpad);
    return result;
  }
}

(2)调度事件(schedule_events)
schedule_events()函数的简单理解是,如果srcpad上还有未发送给sinkpad的事件,先pending,并进行标记,等待pad链接成功之后,再发送给sinkpad

static void
schedule_events (GstPad * srcpad, GstPad * sinkpad)
{
  gint i, len;
  GArray *events;
  PadEvent *ev;
  gboolean pending = FALSE;

  events = srcpad->priv->events;
  len = events->len;

  for (i = 0; i < len; i++) {
    // 遍历srcpad上的事件
    ev = &g_array_index (events, PadEvent, i);
    if (ev->event == NULL)
      continue;
    // 如果sinkpad为空,或者sinkpad上面没有找到相同的事件
    if (sinkpad == NULL || !find_event (sinkpad, ev->event)) {
      ev->received = FALSE;	// 设置为FALSE,表示该事件尚未被sinkpad接收
      pending = TRUE;	// 该事件待处理
    }
  }
  // 存在待处理的事件,将srcpad的flag设置为PENDING_EVENTS
  if (pending)
    GST_OBJECT_FLAG_SET (srcpad, GST_PAD_FLAG_PENDING_EVENTS);
}

2.3 pad激活(gst_pad_set_activate)

pad的激活函数为gst_pad_set_activate(),这是gstreamer中pad激活或停用的核心函数

gboolean
gst_pad_set_active (GstPad * pad, gboolean active)
{
  GstObject *parent;
  GstPadMode old;
  gboolean ret = FALSE;

  g_return_val_if_fail (GST_IS_PAD (pad), FALSE);

  GST_OBJECT_LOCK (pad);
  old = GST_PAD_MODE (pad);
  // 获取pad的父对象
  ACQUIRE_PARENT (pad, parent, no_parent);
  GST_OBJECT_UNLOCK (pad);
  
  if (active) { // 激活pad
    if (old == GST_PAD_MODE_NONE) {
      // 从none状态激活pad
      GST_DEBUG_OBJECT (pad, "activating pad from none");
      ret = (GST_PAD_ACTIVATEFUNC (pad)) (pad, parent);
      if (ret)
        pad->ABI.abi.last_flowret = GST_FLOW_OK;
    } else { // pad已激活,无需再次激活
      GST_DEBUG_OBJECT (pad, "pad was active in %s mode",
          gst_pad_mode_get_name (old));
      ret = TRUE;
    }
  } else { // 停用pad
    if (old == GST_PAD_MODE_NONE) {
      GST_DEBUG_OBJECT (pad, "pad was inactive");
      ret = TRUE;
    } else {
      GST_DEBUG_OBJECT (pad, "deactivating pad from %s mode",
          gst_pad_mode_get_name (old));
      // 停用pad
      ret = activate_mode_internal (pad, parent, old, FALSE);
      if (ret)
        pad->ABI.abi.last_flowret = GST_FLOW_FLUSHING;
    }
  }

  RELEASE_PARENT (parent);

  if (G_UNLIKELY (!ret))
    goto failed;

  return ret;

  /* ERRORS */
no_parent:
  {
    GST_DEBUG_OBJECT (pad, "no parent");
    GST_OBJECT_UNLOCK (pad);
    return FALSE;
  }
failed:
  {
    GST_OBJECT_LOCK (pad);
    if (!active) {
      g_critical ("Failed to deactivate pad %s:%s, very bad",
          GST_DEBUG_PAD_NAME (pad));
    } else {
      GST_WARNING_OBJECT (pad, "Failed to activate pad");
    }
    GST_OBJECT_UNLOCK (pad);
    return FALSE;
  }
}

(1)激活pad(GST_PAD_ACTIVATEFUNC)
GST_PAD_ACTIVATEFUNC指向的是activatefunc()

#define GST_PAD_ACTIVATEFUNC(pad)	(GST_PAD_CAST(pad)->activatefunc)

不同的pad会使用不同的激活类型,例如flv当中的pad,使用的激活函数为gst_flv_demux_sink_activate(),在gst_flv_demux_init()中进行激活函数的配置

static void
gst_flv_demux_init (GstFlvDemux * demux)
{
  // ...
  gst_pad_set_activate_function (demux->sinkpad,
    GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate));
  gst_pad_set_activatemode_function (demux->sinkpad,
    GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_mode));
  // ...
}

gst_flv_demux_sink_activate()的作用是激活demuxer的sink pad

/* If we can pull that's preferred */
static gboolean
gst_flv_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
{
  GstQuery *query;
  gboolean pull_mode;
  // 创建新的查询对象
  query = gst_query_new_scheduling ();
  // 查询peer,就是srcpad的调度能力
  if (!gst_pad_peer_query (sinkpad, query)) {
    gst_query_unref (query);
    goto activate_push;
  }
  // 查询srcpad是否支持pull模式
  pull_mode = gst_query_has_scheduling_mode_with_flags (query,
      GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
  gst_query_unref (query);
  // 如果srcpad不支持pull模式,则激活sinkpad push模式
  if (!pull_mode)
    goto activate_push;

  GST_DEBUG_OBJECT (sinkpad, "activating pull");
  // srcpad支持pull模式,则激活sinkpad的pull模式,保持srcpad和sinkpad具有相同模式
  return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);

activate_push:
  {
    GST_DEBUG_OBJECT (sinkpad, "activating push");
    return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
  }
}

上面代码中有一点需要注意,和常规理解不同,即srcpad处于push模式时,sinkpad也同样处理push模式,而不是pull模式,即srcpad和sinkpad在进行数据传输时,所处的模式是相同的。这样做最大的好处,应该是避免处理复杂的模式转换逻辑,因为当pipeline中链接的元素非常多时,会有大量的srcpad和sinkpad,如果每一次都需要进行模式转换,即srcpad push -> sinkpad pull -> srcpad push -> …,容易出现逻辑错误。

激活模式的函数使用的是gst_pad_activate_mode()

gboolean
gst_pad_activate_mode (GstPad * pad, GstPadMode mode, gboolean active)
{
  GstObject *parent;
  gboolean res;
  GstPadMode old, new;

  g_return_val_if_fail (GST_IS_PAD (pad), FALSE);

  GST_OBJECT_LOCK (pad);
  // 检查old模式是否和要激活的模式一致
  old = GST_PAD_MODE (pad);
  new = active ? mode : GST_PAD_MODE_NONE;
  if (old == new)
    goto was_ok;
  // 检查pad的父对象,如果父对象不存在,打印警告并返回FALSE
  ACQUIRE_PARENT (pad, parent, no_parent);

  GST_OBJECT_UNLOCK (pad);
  // 内部激活函数
  res = activate_mode_internal (pad, parent, mode, active);

  RELEASE_PARENT (parent);

  return res;

was_ok:
  {
    GST_OBJECT_UNLOCK (pad);
    GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "already %s in %s mode",
        active ? "activated" : "deactivated", gst_pad_mode_get_name (mode));
    return TRUE;
  }
no_parent:
  {
    GST_WARNING_OBJECT (pad, "no parent");
    GST_OBJECT_UNLOCK (pad);
    return FALSE;
  }
}

activate_mode_internal()进行激活的主要步骤是:
1.检查激活信息
2.预激活(pre_activate)
3.自定义激活(GST_PAD_ACTIVATEMODEFUNC (pad))
4.后激活(post_activate)

// gst_add_activate_default()给的参数, mode = push, activate = TRUE
static gboolean
activate_mode_internal (GstPad * pad, GstObject * parent, GstPadMode mode,
    gboolean active)
{
  gboolean res = FALSE;
  GstPadMode old, new;
  GstPadDirection dir;
  GstPad *peer;

  GST_OBJECT_LOCK (pad);
  old = GST_PAD_MODE (pad);
  dir = GST_PAD_DIRECTION (pad);
  GST_OBJECT_UNLOCK (pad);

  new = active ? mode : GST_PAD_MODE_NONE;
  // 原始状态和当前状态相同
  if (old == new)
    goto was_ok;
  // pad模式分为PUSH和PULL,检查是否是激活错了方向
  if (active && old != mode && old != GST_PAD_MODE_NONE) {
    /* pad was activate in the wrong direction, deactivate it
     * and reactivate it in the requested mode */
    GST_DEBUG_OBJECT (pad, "deactivating pad from %s mode",
        gst_pad_mode_get_name (old));

    if (G_UNLIKELY (!activate_mode_internal (pad, parent, old, FALSE)))
      goto deactivate_failed;
    old = GST_PAD_MODE_NONE;
  }

  switch (mode) {
    case GST_PAD_MODE_PULL:
    {
      if (dir == GST_PAD_SINK) { // 模式PULL,方向是SINK
        if ((peer = gst_pad_get_peer (pad))) { // 有对端pad,即存在数据发送端
          GST_DEBUG_OBJECT (pad, "calling peer");
          // 激活mode
          if (G_UNLIKELY (!gst_pad_activate_mode (peer, mode, active)))
            goto peer_failed;
          gst_object_unref (peer);
        } else {
          /* there is no peer, this is only fatal when we activate. When we
           * deactivate, we must assume the application has unlinked the peer and
           * will deactivate it eventually. */
          if (active)
            goto not_linked;
          else
            GST_DEBUG_OBJECT (pad, "deactivating unlinked pad");
        }
      } else { // 模式pull,但方向是src
        if (G_UNLIKELY (GST_PAD_GETRANGEFUNC (pad) == NULL))
          goto failure;         /* Can't activate pull on a src without a
                                   getrange function */
      }
      break;
    }
    default:
      break;
  }

  /* Mark pad as needing reconfiguration */
  if (active)
    GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_NEED_RECONFIGURE);

  /* pre_activate returns TRUE if we weren't already in the process of
   * switching to the 'new' mode */
  if (pre_activate (pad, new)) { // 1.预激活,检查是否需要切换到新的模式

    if (GST_PAD_ACTIVATEMODEFUNC (pad)) { // 2.激活mode
      if (G_UNLIKELY (!GST_PAD_ACTIVATEMODEFUNC (pad) (pad, parent, mode,
                  active)))
        goto failure;
    } else {
      /* can happen for sinks of passthrough elements */
    }

    post_activate (pad, new); // 3.后激活,确保模式切换完成之后,pad的状态正确更新
  }

  GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "%s in %s mode",
      active ? "activated" : "deactivated", gst_pad_mode_get_name (mode));

exit_success:
  res = TRUE;
  // ...
}

(1)预激活(pre_activate)

static gboolean
pre_activate (GstPad * pad, GstPadMode new_mode)
{
  switch (new_mode) {
    case GST_PAD_MODE_NONE:
      GST_OBJECT_LOCK (pad);
      // 如果pad已经在激活过程中,等待激活完成
      while (G_UNLIKELY (pad->priv->in_activation))
        g_cond_wait (&pad->priv->activation_cond, GST_OBJECT_GET_LOCK (pad));
      if (new_mode == GST_PAD_MODE (pad)) {
        GST_WARNING_OBJECT (pad,
            "Pad is already in the process of being deactivated");
        GST_OBJECT_UNLOCK (pad);
        return FALSE;
      }
      pad->priv->in_activation = TRUE;
      GST_DEBUG_OBJECT (pad, "setting PAD_MODE NONE, set flushing");
      GST_PAD_SET_FLUSHING (pad);
      pad->ABI.abi.last_flowret = GST_FLOW_FLUSHING;
      // 设置新的mode
      GST_PAD_MODE (pad) = new_mode;
      /* unlock blocked pads so element can resume and stop */
      GST_PAD_BLOCK_BROADCAST (pad);
      GST_OBJECT_UNLOCK (pad);
      break;
    case GST_PAD_MODE_PUSH: // push或pull函数
    case GST_PAD_MODE_PULL:
      GST_OBJECT_LOCK (pad);
      while (G_UNLIKELY (pad->priv->in_activation))
        g_cond_wait (&pad->priv->activation_cond, GST_OBJECT_GET_LOCK (pad));
      if (new_mode == GST_PAD_MODE (pad)) {
        GST_WARNING_OBJECT (pad,
            "Pad is already in the process of being activated");
        GST_OBJECT_UNLOCK (pad);
        return FALSE;
      }
      pad->priv->in_activation = TRUE;
      GST_DEBUG_OBJECT (pad, "setting pad into %s mode, unset flushing",
          gst_pad_mode_get_name (new_mode));
      GST_PAD_UNSET_FLUSHING (pad);
      pad->ABI.abi.last_flowret = GST_FLOW_OK;
      GST_PAD_MODE (pad) = new_mode;
      // 如果pad是sinkpad,并且有peer,需要确保peer上的事件重新调度
      if (GST_PAD_IS_SINK (pad)) {
        GstPad *peer;
        /* make sure the peer src pad sends us all events */
        if ((peer = GST_PAD_PEER (pad))) {
          gst_object_ref (peer);
          GST_OBJECT_UNLOCK (pad);

          GST_DEBUG_OBJECT (pad, "reschedule events on peer %s:%s",
              GST_DEBUG_PAD_NAME (peer));

          GST_OBJECT_LOCK (peer);
          // 调度事件
          schedule_events (peer, NULL);
          GST_OBJECT_UNLOCK (peer);

          gst_object_unref (peer);
        } else {
          GST_OBJECT_UNLOCK (pad);
        }
      } else {
        GST_OBJECT_UNLOCK (pad);
      }
      break;
  }
  return TRUE;
}

(2)激活函数(GST_PAD_ACTIVATEMODEFUNC)
激活函数可以由用户自定义,通过gst_pad_set_activatemode_function_full()进行设置。对于flv demuxer而言,使用的是gst_flv_demux_sink_activate_mode()

static gboolean
gst_flv_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
    GstPadMode mode, gboolean active)
{
  gboolean res;
  GstFlvDemux *demux;

  demux = GST_FLV_DEMUX (parent);

  switch (mode) {
    case GST_PAD_MODE_PUSH: // sink的push模式,实际上是接收srcpad过来的数据流
      // push模式下,sinkpad是被动接受数据的,会将数据传递给内部的解析逻辑
      demux->random_access = FALSE; // 禁用随机访问
      res = TRUE;
      break;
    case GST_PAD_MODE_PULL: // sink的pull模式,实际上是向srcpad发送信息,主动请求数据
      if (active) {
        demux->random_access = TRUE;
        demux->segment_seqnum = gst_util_seqnum_next ();
        // 启动任务gst_flv_demux_loop(),进行数据读取和解析
        res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
            sinkpad, NULL);
      } else {
        demux->random_access = FALSE;
        res = gst_pad_stop_task (sinkpad);
      }
      break;
    default:
      res = FALSE;
      break;
  }
  return res;
}

(3)后激活(post_activate)
后激活函数用于在激活或停用pad之后执行一些清理和后续操作

static void
post_activate (GstPad * pad, GstPadMode new_mode)
{
  switch (new_mode) {
    case GST_PAD_MODE_NONE:
      GST_OBJECT_LOCK (pad);
      pad->priv->in_activation = FALSE;
      g_cond_broadcast (&pad->priv->activation_cond);
      GST_OBJECT_UNLOCK (pad);

      /* ensures that streaming stops */
      GST_PAD_STREAM_LOCK (pad);
      GST_DEBUG_OBJECT (pad, "stopped streaming");
      GST_OBJECT_LOCK (pad);
      remove_events (pad);
      GST_OBJECT_UNLOCK (pad);
      GST_PAD_STREAM_UNLOCK (pad);
      break;
    case GST_PAD_MODE_PUSH:
    case GST_PAD_MODE_PULL:
      GST_OBJECT_LOCK (pad);
      // pad不再处于激活过程中
      pad->priv->in_activation = FALSE;
      // 广播其他线程,激活已经完成
      g_cond_broadcast (&pad->priv->activation_cond);
      GST_OBJECT_UNLOCK (pad);
      /* NOP */
      break;
  }
}

2.4 数据buffer传递(gst_pad_push)

gst_pad_push()和gst_pad_chain()都用于数据传递,但是它们的调用对象和触发机制不同。对于gst_pad_chain()而言,调用流程是

gst_pad_chain() -> gst_pad_chain_data_unchecked() -> chainfunc()

gst_pad_push()的调用流程是

gst_pad_push() -> gst_pad_push_data() -> gst_pad_chain_data_unchecked() -> chainfunc()

通常来说,gst_pad_push()是上层API,直接使用就行。但如果想要自定义链接函数,可以使用gst_pad_chain(),这是一个底层API。另外,gst_pad_push()用于将数据从srcpad推送到下游元素,而gst_pad_chain()用于在sinkpad上处理接收到的数据。

// 入参是srcpad,buffer是srcpad的buffer
GstFlowReturn
gst_pad_push (GstPad * pad, GstBuffer * buffer)
{
  GstFlowReturn res;

  g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR);
  g_return_val_if_fail (GST_PAD_IS_SRC (pad), GST_FLOW_ERROR);
  g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);

  GST_TRACER_PAD_PUSH_PRE (pad, buffer);
  res = gst_pad_push_data (pad,
      GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_PUSH, buffer);
  GST_TRACER_PAD_PUSH_POST (pad, res);
  return res;
}

gst_pad_push_data()执行数据推送操作

static GstFlowReturn
gst_pad_push_data (GstPad * pad, GstPadProbeType type, void *data)
{
  GstPad *peer;
  GstFlowReturn ret;
  gboolean handled = FALSE;

  GST_OBJECT_LOCK (pad);
  /* 状态检查 */
  if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
    goto flushing;

  if (G_UNLIKELY (GST_PAD_IS_EOS (pad)))
    goto eos;

  if (G_UNLIKELY (GST_PAD_MODE (pad) != GST_PAD_MODE_PUSH))
    goto wrong_mode;

#ifdef GST_ENABLE_EXTRA_CHECKS
  if (G_UNLIKELY (pad->priv->last_cookie != pad->priv->events_cookie)) {
    if (!find_event_by_type (pad, GST_EVENT_STREAM_START, 0)) {
      g_warning (G_STRLOC
          ":%s:<%s:%s> Got data flow before stream-start event",
          G_STRFUNC, GST_DEBUG_PAD_NAME (pad));
    }
    if (!find_event_by_type (pad, GST_EVENT_SEGMENT, 0)) {
      g_warning (G_STRLOC
          ":%s:<%s:%s> Got data flow before segment event",
          G_STRFUNC, GST_DEBUG_PAD_NAME (pad));
    }
    pad->priv->last_cookie = pad->priv->events_cookie;
  }
#endif
  // 检查pad上是否有未处理的粘性事件(如stream-start、segment等)
  if (G_UNLIKELY ((ret = check_sticky (pad, NULL))) != GST_FLOW_OK)
    goto events_error;

  /* do block probes */
  // 处理pad上的探针,允许在数据推送前后进行拦截和处理
  PROBE_HANDLE (pad, type | GST_PAD_PROBE_TYPE_BLOCK, data, probe_stopped,
      probe_handled);

  /* recheck sticky events because the probe might have cause a relink */
  if (G_UNLIKELY ((ret = check_sticky (pad, NULL))) != GST_FLOW_OK)
    goto events_error;

  /* do post-blocking probes */
  // 进行probe的回调函数,实际上执行的是do_probe_callbacks()
  PROBE_HANDLE (pad, type, data, probe_stopped, probe_handled);

  /* recheck sticky events because the probe might have cause a relink */
  if (G_UNLIKELY ((ret = check_sticky (pad, NULL))) != GST_FLOW_OK)
    goto events_error;

  if (G_UNLIKELY ((peer = GST_PAD_PEER (pad)) == NULL))
    goto not_linked;

  /* take ref to peer pad before releasing the lock */
  gst_object_ref (peer);
  pad->priv->using++;
  GST_OBJECT_UNLOCK (pad);
  // 执行数据传输
  ret = gst_pad_chain_data_unchecked (peer, type, data);
  data = NULL;

  gst_object_unref (peer);

  GST_OBJECT_LOCK (pad);
  pad->ABI.abi.last_flowret = ret;
  pad->priv->using--;
  if (pad->priv->using == 0) {
    /* pad is not active anymore, trigger idle callbacks */
    PROBE_NO_DATA (pad, GST_PAD_PROBE_TYPE_PUSH | GST_PAD_PROBE_TYPE_IDLE,
        probe_stopped, ret);
  }
  GST_OBJECT_UNLOCK (pad);

  return ret;

  /* ERROR recovery here */
  /* ERRORS */
  // 错误反馈...
}

gst_pad_chain_data_unchecked()将数据data传递到sinkpad

static inline GstFlowReturn
gst_pad_chain_data_unchecked (GstPad * pad, GstPadProbeType type, void *data)
{
  GstFlowReturn ret;
  GstObject *parent;
  gboolean handled = FALSE;

  if (type & GST_PAD_PROBE_TYPE_BUFFER_LIST) {
    // 数据类型为buffer list,调用跟踪链表函数
    GST_TRACER_PAD_CHAIN_LIST_PRE (pad, data);
  } else {
    // 数据类型为buffer,调用跟踪链函数
    GST_TRACER_PAD_CHAIN_PRE (pad, data);
  }

  GST_PAD_STREAM_LOCK (pad);

  GST_OBJECT_LOCK (pad);
  // pad正在刷新
  if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
    goto flushing;
  // pad达到EOS
  if (G_UNLIKELY (GST_PAD_IS_EOS (pad)))
    goto eos;
  // pad不在push模式下
  if (G_UNLIKELY (GST_PAD_MODE (pad) != GST_PAD_MODE_PUSH))
    goto wrong_mode;

#ifdef GST_ENABLE_EXTRA_CHECKS
  if (G_UNLIKELY (pad->priv->last_cookie != pad->priv->events_cookie)) {
    if (!find_event_by_type (pad, GST_EVENT_STREAM_START, 0)) {
      g_warning (G_STRLOC
          ":%s:<%s:%s> Got data flow before stream-start event",
          G_STRFUNC, GST_DEBUG_PAD_NAME (pad));
    }
    if (!find_event_by_type (pad, GST_EVENT_SEGMENT, 0)) {
      g_warning (G_STRLOC
          ":%s:<%s:%s> Got data flow before segment event",
          G_STRFUNC, GST_DEBUG_PAD_NAME (pad));
    }
    pad->priv->last_cookie = pad->priv->events_cookie;
  }
#endif
  // 处理pad上设置的探针(探针可以在数据传递前后进行拦截和处理)
  PROBE_HANDLE (pad, type | GST_PAD_PROBE_TYPE_BLOCK, data, probe_stopped,
      probe_handled);

  PROBE_HANDLE (pad, type, data, probe_stopped, probe_handled);

  ACQUIRE_PARENT (pad, parent, no_parent);
  GST_OBJECT_UNLOCK (pad);

  /* NOTE: we read the chainfunc unlocked.
   * we cannot hold the lock for the pad so we might send
   * the data to the wrong function. This is not really a
   * problem since functions are assigned at creation time
   * and don't change that often... */
  // 数据类型为buffer
  if (G_LIKELY (type & GST_PAD_PROBE_TYPE_BUFFER)) {
    GstPadChainFunction chainfunc;

    if (G_UNLIKELY ((chainfunc = GST_PAD_CHAINFUNC (pad)) == NULL))
      goto no_function;

    GST_CAT_DEBUG_OBJECT (GST_CAT_SCHEDULING, pad,
        "calling chainfunction &%s with buffer %" GST_PTR_FORMAT,
        GST_DEBUG_FUNCPTR_NAME (chainfunc), GST_BUFFER (data));
    // 调用链函数
    ret = chainfunc (pad, parent, GST_BUFFER_CAST (data));

    GST_CAT_DEBUG_OBJECT (GST_CAT_SCHEDULING, pad,
        "called chainfunction &%s with buffer %p, returned %s",
        GST_DEBUG_FUNCPTR_NAME (chainfunc), data, gst_flow_get_name (ret));
  } else { // 数据类型为bufferlist
    GstPadChainListFunction chainlistfunc;

    if (G_UNLIKELY ((chainlistfunc = GST_PAD_CHAINLISTFUNC (pad)) == NULL))
      goto no_function;

    GST_CAT_DEBUG_OBJECT (GST_CAT_SCHEDULING, pad,
        "calling chainlistfunction &%s",
        GST_DEBUG_FUNCPTR_NAME (chainlistfunc));
    // 调用链表函数
    ret = chainlistfunc (pad, parent, GST_BUFFER_LIST_CAST (data));

    GST_CAT_DEBUG_OBJECT (GST_CAT_SCHEDULING, pad,
        "called chainlistfunction &%s, returned %s",
        GST_DEBUG_FUNCPTR_NAME (chainlistfunc), gst_flow_get_name (ret));
  }

  pad->ABI.abi.last_flowret = ret;

  RELEASE_PARENT (parent);

  GST_PAD_STREAM_UNLOCK (pad);

out:
  if (type & GST_PAD_PROBE_TYPE_BUFFER_LIST) {
    GST_TRACER_PAD_CHAIN_LIST_POST (pad, ret);
  } else {
    GST_TRACER_PAD_CHAIN_POST (pad, ret);
  }

  return ret;

  /* ERRORS */
  // 下面是一些错误处理
flushing: // pad正在刷新,丢弃数据
  {
    GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
        "chaining, but pad was flushing");
    pad->ABI.abi.last_flowret = GST_FLOW_FLUSHING;
    GST_OBJECT_UNLOCK (pad);
    GST_PAD_STREAM_UNLOCK (pad);
    gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
    ret = GST_FLOW_FLUSHING;
    goto out;
  }
eos: // pad达到EOS,数据被丢弃
  {
    GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "chaining, but pad was EOS");
    pad->ABI.abi.last_flowret = GST_FLOW_EOS;
    GST_OBJECT_UNLOCK (pad);
    GST_PAD_STREAM_UNLOCK (pad);
    gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
    ret = GST_FLOW_EOS;
    goto out;
  }
wrong_mode: // pad不在push模式下
  {
    g_critical ("chain on pad %s:%s but it was not in push mode",
        GST_DEBUG_PAD_NAME (pad));
    pad->ABI.abi.last_flowret = GST_FLOW_ERROR;
    GST_OBJECT_UNLOCK (pad);
    GST_PAD_STREAM_UNLOCK (pad);
    gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
    ret = GST_FLOW_ERROR;
    goto out;
  }
  // ...
}

对于flv demux,chain function被设置为gst_flv_demux_chain(),这是flv解复用器的核心函数,用于处理从上游元素推送过来的数据。通过状态机解析FLV数据流,并将解析后的数据分发到对应的srcpad。此外,还处理了数据流中的不连续性、刷新、EOS等情况,确保数据流的正确处理。代码太长,就不展开了。

2.5 探针回调(do_probe_callbacks)

探针允许数据流经pad时进行拦截和处理,do_probe_callbacks()的作用是遍历pad上的所有探针,并根据探针的类型和返回值决定数据的处理方式

static GstFlowReturn
do_probe_callbacks (GstPad * pad, GstPadProbeInfo * info,
    GstFlowReturn defaultval)
{
  ProbeMarshall data;
  guint cookie;
  gboolean is_block;
  gulong called_probes[N_STACK_ALLOCATE_PROBES];

  data.pad = pad;
  data.info = info;
  data.pass = FALSE;
  data.handled = FALSE;
  data.dropped = FALSE;

  /* We stack-allocate for N_STACK_ALLOCATE_PROBES hooks as a first step. If more are needed,
   * we will re-allocate with g_malloc(). This should usually never be needed
   */
  data.called_probes = called_probes;
  data.n_called_probes = 0;
  data.called_probes_size = N_STACK_ALLOCATE_PROBES;
  data.retry = FALSE;
  // 检查是否是阻塞探针
  is_block =
      (info->type & GST_PAD_PROBE_TYPE_BLOCK) == GST_PAD_PROBE_TYPE_BLOCK;
  // 如果是阻塞探针,调用do_pad_idle_probe_wait()等待pad空闲
  if (is_block && PROBE_TYPE_IS_SERIALIZED (info)) {
    if (do_pad_idle_probe_wait (pad) == GST_FLOW_FLUSHING)
      goto flushing;
  }

again:
  GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "do probes");
  cookie = pad->priv->probe_list_cookie;

  /* Clear the marshalled flag before doing callbacks. Only if
   * there are matching callbacks still will it get set */
  data.marshalled = FALSE;
  // 遍历pad上的所有探针,并调用每个探针的回调函数
  g_hook_list_marshal (&pad->probes, TRUE,
      (GHookMarshaller) probe_hook_marshal, &data);

  /* if the list changed, call the new callbacks (they will not be in
   * called_probes yet) */
  if (cookie != pad->priv->probe_list_cookie) {
    GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
        "probe list changed, restarting");
    data.retry = TRUE;
    goto again;
  }
  /* 处理探针返回值 */
  /* the first item that dropped will stop the hooks and then we drop here */
  if (data.dropped) // 丢弃数据
    goto dropped;

  /* If one handler took care of it, let the the item pass */
  if (data.handled) { // 数据已经被处理并继续传递
    goto handled;
  }

  /* if no handler matched and we are blocking, let the item pass */
  if (!data.marshalled && is_block) 
    goto passed;

  /* At this point, all handlers returned either OK or PASS. If one handler
   * returned PASS, let the item pass */
  if (data.pass) // 数据继续传递
    goto passed;
  // 阻塞处理
  if (is_block) {
    while (GST_PAD_IS_BLOCKED (pad)) { // 进入阻塞等待状态
      GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
          "we are blocked %d times", pad->num_blocked);

      /* we might have released the lock */
      if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad))) // pad被刷新
        goto flushing;

      /* now we block the streaming thread. It can be unlocked when we
       * deactivate the pad (which will also set the FLUSHING flag) or
       * when the pad is unblocked. A flushing event will also unblock
       * the pad after setting the FLUSHING flag. */
      GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
          "Waiting to be unblocked or set flushing");
      GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_BLOCKING);
      // 阻塞pad的数据流
      GST_PAD_BLOCK_WAIT (pad);
      GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_BLOCKING);
      GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "We got unblocked");

      /* if the list changed, call the new callbacks (they will not be in
       * called_probes yet) */
      if (cookie != pad->priv->probe_list_cookie) {
        GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
            "probe list changed, restarting");
        data.retry = TRUE;
        goto again;
      }

      if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
        goto flushing;
    }
  }

  if (data.called_probes_size > N_STACK_ALLOCATE_PROBES)
    g_free (data.called_probes);

  return defaultval;

  /* ERRORS */
  // 错误的情况
flushing:
  {
    GST_DEBUG_OBJECT (pad, "pad is flushing");
    if (data.called_probes_size > N_STACK_ALLOCATE_PROBES)
      g_free (data.called_probes);
    return GST_FLOW_FLUSHING;
  }
dropped:
  {
    GST_DEBUG_OBJECT (pad, "data is dropped");
    if (data.called_probes_size > N_STACK_ALLOCATE_PROBES)
      g_free (data.called_probes);
    return GST_FLOW_CUSTOM_SUCCESS;
  }
passed:
  {
    /* FIXME : Should we return FLOW_OK or the defaultval ?? */
    GST_DEBUG_OBJECT (pad, "data is passed");
    if (data.called_probes_size > N_STACK_ALLOCATE_PROBES)
      g_free (data.called_probes);
    return GST_FLOW_OK;
  }
handled:
  {
    GST_DEBUG_OBJECT (pad, "data was handled");
    if (data.called_probes_size > N_STACK_ALLOCATE_PROBES)
      g_free (data.called_probes);
    return GST_FLOW_CUSTOM_SUCCESS_1;
  }
}

probe_hook_marshal()的作用是调用注册的pad probe回调函数,并根据回调的返回值执行相应的操作

static void
probe_hook_marshal (GHook * hook, ProbeMarshall * data)
{
  GstPad *pad = data->pad;
  GstPadProbeInfo *info = data->info;
  GstPadProbeType type, flags;
  GstPadProbeCallback callback;
  GstPadProbeReturn ret;
  gpointer original_data;

  flags = hook->flags >> G_HOOK_FLAG_USER_SHIFT;
  type = info->type;
  original_data = info->data;

  /* one of the scheduling types */
  // 检查探针类型与当前数据流是否匹配
  if ((flags & GST_PAD_PROBE_TYPE_SCHEDULING & type) == 0)
    goto no_match;
  // 检查探针是否已经被处理
  if (G_UNLIKELY (data->handled)) {
    GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
        "probe previously returned HANDLED, not calling again");
    goto no_match;
  } else if (G_UNLIKELY (data->dropped)) {
    GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
        "probe previously returned DROPPED, not calling again");
    goto no_match;
  }
  // 根据数据流类型(push或pull)检查探针是否匹配
  if (type & GST_PAD_PROBE_TYPE_PUSH) {
    /* one of the data types for non-idle probes */
    if ((type & GST_PAD_PROBE_TYPE_IDLE) == 0
        && (flags & _PAD_PROBE_TYPE_ALL_BOTH_AND_FLUSH & type) == 0)
      goto no_match;
  } else if (type & GST_PAD_PROBE_TYPE_PULL) {
    /* one of the data types for non-idle probes */
    if ((type & GST_PAD_PROBE_TYPE_BLOCKING) == 0
        && (flags & _PAD_PROBE_TYPE_ALL_BOTH_AND_FLUSH & type) == 0)
      goto no_match;
  } else {
    /* Type must have PULL or PUSH probe types */
    g_assert_not_reached ();
  }

  /* one of the blocking types must match */
  // 检查阻塞类型
  if ((type & GST_PAD_PROBE_TYPE_BLOCKING) &&
      (flags & GST_PAD_PROBE_TYPE_BLOCKING & type) == 0)
    goto no_match;
  if ((type & GST_PAD_PROBE_TYPE_BLOCKING) == 0 &&
      (flags & GST_PAD_PROBE_TYPE_BLOCKING))
    goto no_match;
  /* only probes that have GST_PAD_PROBE_TYPE_EVENT_FLUSH set */
  if ((type & GST_PAD_PROBE_TYPE_EVENT_FLUSH) &&
      (flags & GST_PAD_PROBE_TYPE_EVENT_FLUSH & type) == 0)
    goto no_match;
  // 检查探针是否已经调用,如果探针已经被调用过,设置marshalled标志
  // 并跳转到alread_called标签
  if (check_probe_already_called (hook, data)) {
    /* Reset marshalled = TRUE here, because the probe
     * was already called and set it the first time around,
     * and we may want to keep blocking on it.
     *
     * https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/658
     */
    data->marshalled = TRUE;
    goto already_called;
  }

  GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
      "hook %lu with flags 0x%08x matches", hook->hook_id, flags);

  callback = (GstPadProbeCallback) hook->func;
  if (callback == NULL) {
    /* No callback is equivalent to just returning GST_PAD_PROBE_OK */
    data->marshalled = TRUE;
    return;
  }

  info->id = hook->hook_id;

  if ((flags & GST_PAD_PROBE_TYPE_IDLE))
    pad->priv->idle_running++;

  GST_OBJECT_UNLOCK (pad);
  // 调用探针回调函数
  ret = callback (pad, info, hook->data);

  GST_OBJECT_LOCK (pad);

  /* If the probe callback asked for the
   * probe to be removed, don't set the marshalled flag
   * otherwise, you can get a case where you return
   * GST_PAD_PROBE_REMOVE from a buffer probe and
   * then the pad blocks anyway if there's any other
   * blocking probes installed.
   *
   * https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/658
   */
  if (ret != GST_PAD_PROBE_REMOVE)
    data->marshalled = TRUE;

  if ((flags & GST_PAD_PROBE_TYPE_IDLE))
    pad->priv->idle_running--;

  if (ret != GST_PAD_PROBE_HANDLED && original_data != NULL
      && info->data == NULL) {
    GST_DEBUG_OBJECT (pad, "data item in pad probe info was dropped");
    info->type = GST_PAD_PROBE_TYPE_INVALID;
    data->dropped = TRUE;
  }
  // 处理回调返回值
  switch (ret) {
    case GST_PAD_PROBE_REMOVE:
      /* remove the probe */
      GST_DEBUG_OBJECT (pad, "asked to remove hook");
      cleanup_hook (pad, hook);
      break;
    case GST_PAD_PROBE_DROP:
      /* need to drop the data, make sure other probes don't get called
       * anymore */
      GST_DEBUG_OBJECT (pad, "asked to drop item");
      info->type = GST_PAD_PROBE_TYPE_INVALID;
      data->dropped = TRUE;
      break;
    case GST_PAD_PROBE_HANDLED:
      GST_DEBUG_OBJECT (pad, "probe handled data");
      data->handled = TRUE;
      break;
    case GST_PAD_PROBE_PASS:
      /* inform the pad block to let things pass */
      GST_DEBUG_OBJECT (pad, "asked to pass item");
      data->pass = TRUE;
      break;
    case GST_PAD_PROBE_OK:
      GST_DEBUG_OBJECT (pad, "probe returned OK");
      break;
    default:
      GST_DEBUG_OBJECT (pad, "probe returned %d", ret);
      break;
  }
  return;

no_match:
  {
    GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
        "hook %lu with flags 0x%08x does not match %08x",
        hook->hook_id, flags, info->type);
    return;
  }
already_called:
  {
    GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
        "hook %lu already called", hook->hook_id);
    return;
  }
}

2.6 事件转发(gst_pad_forward)

gst_pad_forward()的作用是将事件从一个pad转发到另一个pad中,例如从上游元素的srcpad转发事件到下游元素的sinkpad。

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;
  // pad的迭代器
  iter = gst_pad_iterate_internal_links (pad);

  if (!iter)
    goto no_iter;
  // 遍历内部链接的pads
  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 */
        // 如果当前pad已经处理过,跳过
        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));
        // 回调forward,处理当前pad
        done = result = forward (intpad, user_data);
		// 将当前pad添加到已处理的pads列表中
        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;
}

上面的forward()函数,在gstpad.c中可以使用event_forward_func(),用于将事件传递给目标pad

// pad是目标pad,需要将data传递给这个pad
// data包含事件和处理结果
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));
  // 将event发送给pad
  data->result |= gst_pad_push_event (pad, gst_event_ref (data->event));

  data->dispatched = TRUE;

  /* don't stop */
  return FALSE;
}

gst_pad_push_event()通常用于元素之间事件的传递,下层会继续调用核心传递函数gst_pad_push_event_unchecked()、gst_pad_send_event_unchecked()等,最终使用pre_eventfunc_check()、eventfullfunc()和实现事件对应的操作,后续涉及到具体的事件,因为太多这里就不展开

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值