1 GstElement基本概念

  • GstElement是构建可用于GStreamer管道的元素所需的抽象基类(不可实例化)。有关创建GstElement子类的更多信息,请参阅插件编写指南。

  • 使用gst_element_get_name可以获取GstElement的名称,并使用gst_element_set_name进行设置。为了提高速度,在核心中使用GST_ELEMENT_NAME时,需要使用适当的锁。不要在插件或应用程序中使用此功能,以保留ABI兼容性。

  • 元素可以拥有GstPad类型的pad。这些pad链接到其他元素上的pad。GstBuffer在这些链接的pad之间流动。GstElement具有GstPad结构的GList,用于其所有输入(或sink)和输出(或source)pad。核心和插件编写者可以使用gst_element_add_pad和gst_element_remove_pad来添加和删除pad。

  • 可以使用gst_element_get_static_pad按名称检索元素的现有pad。可以使用gst_element_request_pad和GstPadTemplate创建一个新的动态pad。可以使用gst_element_iterate_pads获取所有pad的迭代器。

  • 通过它们的pad可以将元素链接在一起。如果链接很简单,可以使用gst_element_link方便函数链接两个元素,或使用gst_element_link_many链接多个元素。使用gst_element_link_filtered按指定的一组GstCaps约束链接两个元素。为了更精细地控制,可以使用gst_element_link_pads和gst_element_link_pads_filtered按名称指定每个元素上要链接的pad。

  • 每个元素都有一个状态(参见GstState)。可以使用gst_element_get_state和gst_element_set_state获取和设置元素的状态。设置状态会触发GstStateChange。要获取GstState的字符串表示形式,请使用gst_element_state_get_name。

  • 可以使用gst_element_get_clock和gst_element_set_clock在元素上获取和设置GstClock。如果设置了GST_ELEMENT_FLAG_PROVIDE_CLOCK标志,一些元素可以为管道提供时钟。可以使用gst_element_provide_clock方法检索由这种元素提供的时钟。并非所有元素都需要时钟才能正确运行。如果设置了GST_ELEMENT_FLAG_REQUIRE_CLOCK()标志,则应该使用gst_element_set_clock在元素上设置时钟。

  • 请注意,时钟的选择和分发通常由顶级的GstPipeline处理,因此时钟函数只能在非常特定的情况下使用。

2 GstElement类型结构

2.1 GstElement类型注册宏定义

/* filename: gstelement.h */
#define GST_TYPE_ELEMENT                (gst_element_get_type ())

/* filename: gstelement.c */
gst_element_get_type (void)
{
  static gsize gst_element_type = 0;

  if (g_once_init_enter (&gst_element_type)) {
    GType _type;
    static const GTypeInfo element_info = {
      sizeof (GstElementClass),
      gst_element_base_class_init,
      NULL,                     /* base_class_finalize */
      (GClassInitFunc) gst_element_class_init,
      NULL,
      NULL,
      sizeof (GstElement),
      0,
      (GInstanceInitFunc) gst_element_init,
      NULL
    };

    _type = g_type_register_static (GST_TYPE_OBJECT, "GstElement",
        &element_info, G_TYPE_FLAG_ABSTRACT);

    __gst_elementclass_factory =
        g_quark_from_static_string ("GST_ELEMENTCLASS_FACTORY");
    __gst_elementclass_skip_doc =
        g_quark_from_static_string ("GST_ELEMENTCLASS_SKIP_DOCUMENTATION");
    g_once_init_leave (&gst_element_type, _type);
  }
  return gst_element_type;
}

2.2 GstElement类型相关枚举

2.2.1 GstState

/* gstelement.h */

/**
 * 元素可能处于的状态。可以使用gst_element_set_state()更改状态,并使用gst_element_get_state()检查状态。
 */
typedef enum {
  GST_STATE_VOID_PENDING        = 0,
  /* NULL状态或元素的初始状态。 */
  GST_STATE_NULL                = 1,
  /* 元素已经准备好进入暂停状态。 */
  GST_STATE_READY               = 2,
  /* 元素暂停时,它已准备好接受和处理数据。然而,Sink元素只接受一个缓冲区,然后阻塞。 */
  GST_STATE_PAUSED              = 3,
  /* 元素是PLAYING, #GstClock正在运行,数据正在流动。 */
  GST_STATE_PLAYING             = 4
} GstState;

2.2.2 GstStateChangeReturn

/* gstelement.h */

/**
 * 状态更改函数(如gst_element_set_state())的可能返回值。只有@GST_STATE_CHANGE_FAILURE才是真正的失败。
 */
typedef enum {
  GST_STATE_CHANGE_FAILURE             = 0,
  GST_STATE_CHANGE_SUCCESS             = 1,
  /* 状态更改将异步发生 */
  GST_STATE_CHANGE_ASYNC               = 2,
  /* 状态更改成功,但元素无法产生%GST_STATE_PAUSED中的数据。这通常发生在实时资源上。 */
  GST_STATE_CHANGE_NO_PREROLL          = 3
} GstStateChangeReturn;

2.2.3 GstStateChangeReturn

/* gstelement.h */

/**
 * GstStateChange:
 * @GST_STATE_CHANGE_NULL_TO_READY    : 从NULL状态到READY状态的状态改变。
 *   1. 元素必须检查所需的资源是否可用。设备的sink和source通常会尝试探测设备以限制它们的caps。
 *   2. 元素打开设备(以便一些特性可以被probe)。
 * @GST_STATE_CHANGE_READY_TO_PAUSED  : 从READY状态到PAUSED状态的状态改变。
 *   1. 元素的pad被激活以准备接收数据。开始流线程。
 *   2. 一些元素可能需要返回%GST_STATE_CHANGE_ASYNC,并在有足够信息时完成状态改变。对于sink来说,返回%GST_STATE_CHANGE_ASYNC
 *     当它们收到第一个缓冲区或%GST_EVENT_EOS(预滚动)时,完成状态改变。
 *     在PAUSED状态下,当收到第一个缓冲区或%GST_EVENT_EOS(预滚动)时,sink还会阻塞数据流。 
 *   3. 管道将running_time重置为0。
 *   4. 实时源返回%GST_STATE_CHANGE_NO_PREROLL并且不生成数据。
 * @GST_STATE_CHANGE_PAUSED_TO_PLAYING: 从PAUSED状态到PLAYING状态的状态改变。
 *   1. 大多数元素忽略此状态改变。
 *   2. 管道选择一个#GstClock并在将其设置为PLAYING之前将其分发给所有子元素。这意味着只允许在PLAYING状态下对#GstClock进行同步。
 *   3. 管道使用 #GstClock和 running_time来计算base_time。在执行状态改变时,将base_time分发给所有子元素。
 *   4. Sink元素停止在预滚动prepoll缓冲区或事件上阻塞,并开始渲染数据。
 *   5. The pipeline uses the #GstClock and the running_time to calculate the
 *   6. Sink可以在PLAYING状态下发布%GST_MESSAGE_EOS。不允许在不是PLAYING状态时发布%GST_MESSAGE_EOS。
 *   7. 在PAUSED或PLAYING状态中进行流式传输时,元素有时会创建和移除pad。
 *   8. 实时源开始生成数据并返回%GST_STATE_CHANGE_SUCCESS。
 * 
 * @GST_STATE_CHANGE_PLAYING_TO_PAUSED: 从 PLAYING 到 PAUSED 的状态变化。
 *   1. Sink 解除所有 #GstClock 的等待调用。
 *   2. 当 Sink 没有待播放的缓冲区时,它会从此状态变化返回 #GST_STATE_CHANGE_ASYNC,并在接收到新的缓冲区或 %GST_EVENT_EOS 时完成状态变化。
 *   3. 任何排队的 %GST_MESSAGE_EOS 都会被移除,因为它们将在返回 PLAYING 状态时重新发布。这些 EOS 消息被排在 #GstBin 容器中。
 *   4. 实时源停止生成数据并返回 %GST_STATE_CHANGE_NO_PREROLL。
 * @GST_STATE_CHANGE_PAUSED_TO_READY  : 从 PAUSED 到 READY 的状态变化。
 *   1. Sink 解除 preroll 中的所有等待。
 *   2. 元素解除设备上的所有等待。
 *   3. Chain 或 get_range 函数返回 %GST_FLOW_FLUSHING。
 *   4. 元素的 pads 被停用,因此无法进行流传输,并停止所有流传输线程。
 *   5. Sink 忘记所有已协商的格式。
 *   6. 元素移除所有 sometimes pads。
 * @GST_STATE_CHANGE_READY_TO_NULL    : 从 READY 到 NULL 的状态变化。
 *   1. 元素关闭设备。
 *   2. 元素重置任何内部状态。
 * 
 * @GST_STATE_CHANGE_NULL_TO_NULL       : state change from NULL to NULL. (Since: 1.14)
 * @GST_STATE_CHANGE_READY_TO_READY     : state change from READY to READY,
 * This might happen when going to PAUSED asynchronously failed, in that case
 * 这可能发生在异步转换到 PAUSED 失败的情况下,在这种情况下,元素应确保它们处于适当、一致的 READY 状态。 (自 1.14 版本开始)
 * @GST_STATE_CHANGE_PAUSED_TO_PAUSED   : state change from PAUSED to PAUSED.
 * 这可能发生在元素处于 PLAYING 状态但是 'lost state' 的情况下,它们应确保返回真正的 'PAUSED' 状态(例如,预滚动)。 (自 1.14 版本开始)
 * @GST_STATE_CHANGE_PLAYING_TO_PLAYING : state change from PLAYING to PLAYING. (Since: 1.14)
 *
 * 这些是元素经历的不同状态变化。
 * %GST_STATE_NULL ⇒ %GST_STATE_PLAYING 被称为上升状态变化,
 * 而 %GST_STATE_PLAYING ⇒ %GST_STATE_NULL 则是下降状态变化。
 */
typedef enum /*< flags=0 >*/
{
  GST_STATE_CHANGE_NULL_TO_READY        = (GST_STATE_NULL<<3) | GST_STATE_READY,
  GST_STATE_CHANGE_READY_TO_PAUSED      = (GST_STATE_READY<<3) | GST_STATE_PAUSED,
  GST_STATE_CHANGE_PAUSED_TO_PLAYING    = (GST_STATE_PAUSED<<3) | GST_STATE_PLAYING,

  GST_STATE_CHANGE_PLAYING_TO_PAUSED    = (GST_STATE_PLAYING<<3) | GST_STATE_PAUSED,
  GST_STATE_CHANGE_PAUSED_TO_READY      = (GST_STATE_PAUSED<<3) | GST_STATE_READY,
  GST_STATE_CHANGE_READY_TO_NULL        = (GST_STATE_READY<<3) | GST_STATE_NULL,

  GST_STATE_CHANGE_NULL_TO_NULL         = (GST_STATE_NULL<<3) | GST_STATE_NULL,
  GST_STATE_CHANGE_READY_TO_READY       = (GST_STATE_READY<<3) | GST_STATE_READY,
  GST_STATE_CHANGE_PAUSED_TO_PAUSED     = (GST_STATE_PAUSED<<3) | GST_STATE_PAUSED,
  GST_STATE_CHANGE_PLAYING_TO_PLAYING   = (GST_STATE_PLAYING<<3) | GST_STATE_PLAYING
} GstStateChange;

2.2.4 GstStateChangeReturn

/* gstelement.h */

/**
 * GstElementFlags:
 * @GST_ELEMENT_FLAG_LOCKED_STATE: ignore state changes from parent
 * @GST_ELEMENT_FLAG_SINK: the element is a sink
 * @GST_ELEMENT_FLAG_SOURCE: the element is a source.
 * @GST_ELEMENT_FLAG_PROVIDE_CLOCK: the element can provide a clock
 * @GST_ELEMENT_FLAG_REQUIRE_CLOCK: the element requires a clock
 * @GST_ELEMENT_FLAG_INDEXABLE: the element can use an index
 * @GST_ELEMENT_FLAG_LAST: offset to define more flags
 *
 * 元素可能具有的标准flags。
 */
typedef enum
{
  GST_ELEMENT_FLAG_LOCKED_STATE   = (GST_OBJECT_FLAG_LAST << 0),
  GST_ELEMENT_FLAG_SINK           = (GST_OBJECT_FLAG_LAST << 1),
  GST_ELEMENT_FLAG_SOURCE         = (GST_OBJECT_FLAG_LAST << 2),
  GST_ELEMENT_FLAG_PROVIDE_CLOCK  = (GST_OBJECT_FLAG_LAST << 3),
  GST_ELEMENT_FLAG_REQUIRE_CLOCK  = (GST_OBJECT_FLAG_LAST << 4),
  GST_ELEMENT_FLAG_INDEXABLE      = (GST_OBJECT_FLAG_LAST << 5),
  /* padding */
  GST_ELEMENT_FLAG_LAST           = (GST_OBJECT_FLAG_LAST << 10)
} GstElementFlags;

2.3 GstElement相关结构体

2.3.1 GstElement

/**
 * GstElement:
 * @state_lock: 多线程执行  gst_element_set_state() 的锁
 * @state_cond: 通知其它条件锁等待,状态改变完成
 * @state_cookie: 用于检测 gst_element_set_state() 和 gst_element_get_state() 的并发执行
 * @target_state: 应用程序设置的元素的目标状态
 * @current_state: 元素当前的状态
 * @next_state: 元素的下一个状态,如果元素正处于正确的状态,则可以是 #GST_STATE_VOID_PENDING
 * @pending_state: 元素应该转换到的最终状态,如果元素处于正确的状态,则可以是 #GST_STATE_VOID_PENDING
 * @last_return: 元素状态改变的最后返回值
 * @bus: 元素的bus总线,这个总线由父元素或应用程序提供给元素。#GstPipeline 有自己的总线。
 * @clock: 元素的时钟。通常由顶层 #GstPipeline 提供给元素。
 * @base_time: 元素设置为 PLAYING 之前时钟的时间。在 PLAYING 状态下,从当前时钟时间减去 @base_time 将得到相对于时钟的 running_time。
 * @start_time: 上一个 PAUSED 状态的 running_time
 * @numpads: pads的数量,包括source pads和sink pads.
 * @pads: (element-type Gst.Pad): 存储pads的列表
 * @numsrcpads: source pads的数量
 * @srcpads: (element-type Gst.Pad): source pads的数列表
 * @numsinkpads: sink pads的数量
 * @sinkpads: (element-type Gst.Pad): sink pads的列表
 * @pads_cookie: 每当添加或移除一个 pad 时更新
 * @contexts: (element-type Gst.Context): 上下文列表
 *
 * GStreamer element abstract base class.
 */
struct _GstElement
{
  GstObject             object; /* 用于 */

  /*< public >*/ /* with LOCK */
  GRecMutex             state_lock;

  /* element state */
  GCond                 state_cond;
  guint32               state_cookie; /* 每次设定元素到新的状态,这个值就会加一(增量值,不会减少) */
  GstState              target_state; /* 应用程序设定的元素目标状态,元素目标状态不应该和pengding_state相同吗?? */
  GstState              current_state; /* 元素当前状态 */
  GstState              next_state; /* 元素的下一个状态,如果元素正处于正确的状态,则可以是 #GST_STATE_VOID_PENDING */
  GstState              pending_state; /* 元素应该转换到的最终状态,如果元素处于正确的状态,则可以是 #GST_STATE_VOID_PENDING */
  GstStateChangeReturn  last_return; /* 上一次状态改变后的返回值 */

  GstBus               *bus;

  /* allocated clock */
  GstClock             *clock;
  GstClockTimeDiff      base_time; /* NULL/READY: 0 - PAUSED: current time - PLAYING: difference to clock */
  GstClockTime          start_time;

  /* element pads, these lists can only be iterated while holding
   * the LOCK or checking the cookie after each LOCK. */
  guint16               numpads;
  GList                *pads;
  guint16               numsrcpads;
  GList                *srcpads;
  guint16               numsinkpads;
  GList                *sinkpads;
  guint32               pads_cookie;

  /* with object LOCK */
  GList                *contexts;

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

2.3.2 GstElementClass

/**
 * GstElementClass:
 * @parent_class: the parent class structure
 * @metadata: 此类元素的元数据
 * @elementfactory: 创建这些元素的 #GstElementFactory
 * @padtemplates:  #GstPadTemplate 的 #GList
 * @numpadtemplates: padtemplates 的数量
 * @pad_templ_cookie:  每当 padtemplates 更改时都会更改
 * @request_new_pad: 请求新 pad 时调用
 * @release_pad: 当请求 pad 要释放时调用
 * @get_state: 获取元素的状态
 * @set_state: 在元素上设置新状态
 * @change_state: 被 @set_state 调用以执行增量状态更改
 * @set_bus: 在元素上设置 #GstBus
 * @provide_clock: 获取元素提供的 #GstClock
 * @set_clock: 在元素上设置 #GstClock
 * @send_event: 向元素发送 #GstEvent
 * @query: 在元素上执行 #GstQuery
 * @state_changed: 在设置新状态后立即调用。
 * @post_message: 在元素上发布消息时调用。链接到父类的处理程序以将其发布到总线上。
 * @set_context: 在元素上设置 #GstContext
 *
 * 重写以上虚函数以实现用户定义元素的功能
 */
struct _GstElementClass
{
  GstObjectClass         parent_class;

  /*< public >*/
  /* the element metadata */
  gpointer		 metadata;

  /* factory that the element was created from */
  GstElementFactory     *elementfactory;

  /* templates for our pads */
  GList                 *padtemplates;
  gint                   numpadtemplates;
  guint32                pad_templ_cookie;

  /*< private >*/
  /* signal callbacks */
  void (*pad_added)     (GstElement *element, GstPad *pad);
  void (*pad_removed)   (GstElement *element, GstPad *pad);
  void (*no_more_pads)  (GstElement *element);

  /*< public >*/
  /* virtual methods for subclasses */

  /* request/release pads */
  /* FIXME 2.0 harmonize naming with gst_element_request_pad */
  GstPad*               (*request_new_pad)      (GstElement *element, GstPadTemplate *templ,
                                                 const gchar* name, const GstCaps *caps);

  void                  (*release_pad)          (GstElement *element, GstPad *pad);

  /* state changes */
  GstStateChangeReturn (*get_state)             (GstElement * element, GstState * state,
                                                 GstState * pending, GstClockTime timeout);
  GstStateChangeReturn (*set_state)             (GstElement *element, GstState state);
  GstStateChangeReturn (*change_state)          (GstElement *element, GstStateChange transition);
  void                 (*state_changed)         (GstElement *element, GstState oldstate,
                                                 GstState newstate, GstState pending);

  /* bus */
  void                  (*set_bus)              (GstElement * element, GstBus * bus);

  /* set/get clocks */
  GstClock*             (*provide_clock)        (GstElement *element);
  gboolean              (*set_clock)            (GstElement *element, GstClock *clock);

  /* query functions */
  gboolean              (*send_event)           (GstElement *element, GstEvent *event);

  gboolean              (*query)                (GstElement *element, GstQuery *query);

  gboolean              (*post_message)         (GstElement *element, GstMessage *message);

  void                  (*set_context)          (GstElement *element, GstContext *context);

  /*< private >*/
  gpointer _gst_reserved[GST_PADDING_LARGE-2];
};

3 GstElement对象相关函数