【GStreamer】GstElement的简单分析

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

GstElement是GStreamer中最核心的构建块,代表一个功能单元,用于处理多媒体数据流。每个元素都有特定的功能,例如source elements用于生成数据(摄像头读取视频)、filter elements用于处理数据(编解码、格式转换等)、sink elements用于接收数据(视频渲染到屏幕),GStreamer通过组合不同的GstElement来构建复杂的多媒体处理流程

1.类定义

(1)状态机

typedef enum {
  GST_STATE_VOID_PENDING        = 0,
  GST_STATE_NULL                = 1, // 初始状态,元素未被初始化
  GST_STATE_READY               = 2, // 元素已初始化,但未开始处理数据
  GST_STATE_PAUSED              = 3, // 元素已经准备好处理数据,但数据流被暂停
  GST_STATE_PLAYING             = 4  // 元素正在处理数据
} GstState;

(2)状态转换机

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;

(3)元素标志
描述元素的行为和特性,用于在运行时检查元素的状态或配置

typedef enum
{
  // 元素状态被锁定
  GST_ELEMENT_FLAG_LOCKED_STATE   = (GST_OBJECT_FLAG_LAST << 0),
  // 元素为sink元素
  GST_ELEMENT_FLAG_SINK           = (GST_OBJECT_FLAG_LAST << 1),
  // 元素为source元素
  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;

(4)GstElement
GstElement是所有元素的基类,包括source,filter和sink

struct _GstElement
{
  GstObject             object;

  /*< public >*/ /* with LOCK */
  // 元素状态锁(递归互斥锁)
  GRecMutex             state_lock;

  /* element state */
  // 状态变化条件变量
  GCond                 state_cond;
  // 检测状态变化的版本号
  guint32               state_cookie;
  // 目标状态
  GstState              target_state;
  // 当前状态
  GstState              current_state;
  // 下一个状态
  GstState              next_state;
  // 挂起状态
  GstState              pending_state;
  // 上一次状态变化的返回值
  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. */
  // pad的总数
  guint16               numpads;
  // 所有pad的链表
  GList                *pads;
  // srcpad的数量
  guint16               numsrcpads;
  // srcpads的链表
  GList                *srcpads;
  // sinkpad的数量
  guint16               numsinkpads;
  // sinkpads的链表
  GList                *sinkpads;
  // pad列表的版本号,用于检测pad列表的变化
  guint32               pads_cookie;

  /* with object LOCK */
  // 元素的上下文列表,用于管理元素的运行时上下文
  GList                *contexts;

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

(5)GstElementClass

struct _GstElementClass
{
  GstObjectClass         parent_class;

  /*< public >*/
  /* the element metadata */
  // 元数据,包含元素的描述信息
  gpointer		 metadata;

  /* factory that the element was created from */
  // 管理元素的创建和销毁
  GstElementFactory     *elementfactory;

  /* templates for our pads */
  // pad模板链表,描述元素支持的pad类型
  GList                 *padtemplates;
  // pad模板的数量
  gint                   numpadtemplates;
  // pad模板列表的版本号,用于检测pad模板列表的变化
  guint32                pad_templ_cookie;

  /*< private >*/
  /* signal callbacks */
  // pad添加到元素时的回调
  void (*pad_added)     (GstElement *element, GstPad *pad);
  // pad移除时的回调
  void (*pad_removed)   (GstElement *element, GstPad *pad);
  // 不再添加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 */
  // 请求一个新pad,根据给定的模板和名称创建pad
  GstPad*               (*request_new_pad)      (GstElement *element, GstPadTemplate *templ,
                                                 const gchar* name, const GstCaps *caps);
  // 释放一个pad,将其从元素中移除
  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];
};

2.函数定义

2.1 初始化

(1)gst_element_base_class_init()
初始化元素的基类,通常在元素类被首次创建时调用(被注册到GStreamer时,通常是插件加载时),用于设置类的默认行为

static void
gst_element_base_class_init (gpointer g_class)
{
  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
  GList *node, *padtemplates;

  /* Copy the element details here so elements can inherit the
   * details from their base class and classes only need to set
   * the details in class_init instead of base_init */
  // 设置metadata
  element_class->metadata =
      element_class->metadata ? gst_structure_copy (element_class->metadata) :
      gst_structure_new_empty ("metadata");

  /* Copy the pad templates so elements inherit them
   * from their base class but elements can add pad templates in class_init
   * instead of base_init.
   */
  // 复制基类的pad模板链表
  padtemplates = g_list_copy (element_class->padtemplates);
  for (node = padtemplates; node != NULL; node = node->next) {
    GstPadTemplate *tmpl = (GstPadTemplate *) node->data;
    gst_object_ref (tmpl);
  }
  element_class->padtemplates = padtemplates;

  /* set the factory, see gst_element_register() */
  // 初始化工厂信息
  element_class->elementfactory =
      g_type_get_qdata (G_TYPE_FROM_CLASS (element_class),
      __gst_elementclass_factory);
  GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "type %s : factory %p",
      G_OBJECT_CLASS_NAME (element_class), element_class->elementfactory);
}

(2)gst_element_class_init()
初始化元素的类,通常在元素类被首次创建时调用(被注册到GStreamer时,通常是插件加载时),用于设置元素的元数据、信号、属性、pad模板等

static void
gst_element_class_init (GstElementClass * klass)
{
  GObjectClass *gobject_class;

  gobject_class = (GObjectClass *) klass;

  parent_class = g_type_class_peek_parent (klass);

  /**
   * GstElement::pad-added:
   * @gstelement: the object which received the signal
   * @new_pad: the pad that has been added
   *
   * a new #GstPad has been added to the element. Note that this signal will
   * usually be emitted from the context of the streaming thread. Also keep in
   * mind that if you add new elements to the pipeline in the signal handler
   * you will need to set them to the desired target state with
   * gst_element_set_state() or gst_element_sync_state_with_parent().
   */
  // 添加pad时的信号
  gst_element_signals[PAD_ADDED] =
      g_signal_new ("pad-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
      G_STRUCT_OFFSET (GstElementClass, pad_added), NULL, NULL,
      NULL, G_TYPE_NONE, 1, GST_TYPE_PAD);
  /**
   * GstElement::pad-removed:
   * @gstelement: the object which received the signal
   * @old_pad: the pad that has been removed
   *
   * a #GstPad has been removed from the element
   */
  // 移除pad时的信号
  gst_element_signals[PAD_REMOVED] =
      g_signal_new ("pad-removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
      G_STRUCT_OFFSET (GstElementClass, pad_removed), NULL, NULL,
      NULL, G_TYPE_NONE, 1, GST_TYPE_PAD);
  /**
   * GstElement::no-more-pads:
   * @gstelement: the object which received the signal
   *
   * This signals that the element will not generate more dynamic pads.
   * Note that this signal will usually be emitted from the context of
   * the streaming thread.
   */
  // 不期望再添加pad时的信号
  gst_element_signals[NO_MORE_PADS] =
      g_signal_new ("no-more-pads", G_TYPE_FROM_CLASS (klass),
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstElementClass, no_more_pads), NULL,
      NULL, NULL, G_TYPE_NONE, 0);
  // 构造和析构函数
  gobject_class->dispose = gst_element_dispose;
  gobject_class->finalize = gst_element_finalize;
  gobject_class->constructed = gst_element_constructed;
  // element的一些默认函数
  klass->change_state = GST_DEBUG_FUNCPTR (gst_element_change_state_func);
  klass->set_state = GST_DEBUG_FUNCPTR (gst_element_set_state_func);
  klass->get_state = GST_DEBUG_FUNCPTR (gst_element_get_state_func);
  klass->set_clock = GST_DEBUG_FUNCPTR (gst_element_set_clock_func);
  klass->set_bus = GST_DEBUG_FUNCPTR (gst_element_set_bus_func);
  klass->query = GST_DEBUG_FUNCPTR (gst_element_default_query);
  klass->send_event = GST_DEBUG_FUNCPTR (gst_element_default_send_event);
  klass->numpadtemplates = 0;
  klass->post_message = GST_DEBUG_FUNCPTR (gst_element_post_message_default);
  klass->set_context = GST_DEBUG_FUNCPTR (gst_element_set_context_default);

  klass->elementfactory = NULL;
}

(3)gst_element_init()
初始化元素的实例,它在每次创建元素的新实例时调用(例如gst_element_factory_make()),用于设置实例的初始状态和属性

static void
gst_element_init (GstElement * element)
{
  GST_STATE (element) = GST_STATE_NULL;
  GST_STATE_TARGET (element) = GST_STATE_NULL;
  GST_STATE_NEXT (element) = GST_STATE_VOID_PENDING;
  GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING;
  GST_STATE_RETURN (element) = GST_STATE_CHANGE_SUCCESS;

  g_rec_mutex_init (&element->state_lock);
  g_cond_init (&element->state_cond);
}

2.2 对pad的操作

(1)向element中添加pad

gboolean
gst_element_add_pad (GstElement * element, GstPad * pad)
{
  gchar *pad_name;
  gboolean active;
  gboolean should_activate;

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

  /* locking pad to look at the name */
  // 检查pad的名称和激活状态
  GST_OBJECT_LOCK (pad);
  pad_name = g_strdup (GST_PAD_NAME (pad));
  GST_CAT_INFO_OBJECT (GST_CAT_ELEMENT_PADS, element, "adding pad '%s'",
      GST_STR_NULL (pad_name));
  active = GST_PAD_IS_ACTIVE (pad);
  GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_NEED_PARENT);
  GST_OBJECT_UNLOCK (pad);

  /* then check to see if there's already a pad by that name here */
  // 检查是否有同名的pad
  GST_OBJECT_LOCK (element);
  if (G_UNLIKELY (!gst_object_check_uniqueness (element->pads, pad_name)))
    goto name_exists;

  /* try to set the pad's parent */
  // 将element设置为pad的父元素
  if (G_UNLIKELY (!gst_object_set_parent (GST_OBJECT_CAST (pad),
              GST_OBJECT_CAST (element))))
    goto had_parent;

  /* check for active pads */
  // 当前状态是非激活,但是期望要激活
  should_activate = !active && (GST_STATE (element) > GST_STATE_READY ||
      GST_STATE_NEXT (element) == GST_STATE_PAUSED);

  g_free (pad_name);

  /* add it to the list */
  // 检查pad的方向,并添加到对应的列表之中
  switch (gst_pad_get_direction (pad)) {
    case GST_PAD_SRC:
      element->srcpads = g_list_append (element->srcpads, pad);
      element->numsrcpads++;
      break;
    case GST_PAD_SINK:
      element->sinkpads = g_list_append (element->sinkpads, pad);
      element->numsinkpads++;
      break;
    default:
      goto no_direction;
  }
  // 无论pad的方向,添加到整体的链表当中
  element->pads = g_list_append (element->pads, pad);
  element->numpads++;
  element->pads_cookie++;
  GST_OBJECT_UNLOCK (element);
  // 当前pad应该被激活,进行状态激活
  if (should_activate)
    gst_pad_set_active (pad, TRUE);

  /* emit the PAD_ADDED signal */
  // 发布信号,表示element中已经添加了一个pad
  g_signal_emit (element, gst_element_signals[PAD_ADDED], 0, pad);
  GST_TRACER_ELEMENT_ADD_PAD (element, pad);
  return TRUE;

  /* ERROR cases */
name_exists:
  {
    g_critical ("Padname %s is not unique in element %s, not adding",
        pad_name, GST_ELEMENT_NAME (element));
    GST_OBJECT_UNLOCK (element);
    g_free (pad_name);
    gst_object_ref_sink (pad);
    gst_object_unref (pad);
    return FALSE;
  }
had_parent:
  {
    g_critical
        ("Pad %s already has parent when trying to add to element %s",
        pad_name, GST_ELEMENT_NAME (element));
    GST_OBJECT_UNLOCK (element);
    g_free (pad_name);
    return FALSE;
  }
no_direction:
  {
    GST_OBJECT_LOCK (pad);
    g_critical
        ("Trying to add pad %s to element %s, but it has no direction",
        GST_OBJECT_NAME (pad), GST_ELEMENT_NAME (element));
    GST_OBJECT_UNLOCK (pad);
    GST_OBJECT_UNLOCK (element);
    return FALSE;
  }
}

(2)gst_element_remove_pad()
从element中移除一个pad,这个函数确保pad被正确地从元素中分离,并触发相关的信号和清理操作

gboolean
gst_element_remove_pad (GstElement * element, GstPad * pad)
{
  GstPad *peer;

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

  /* locking pad to look at the name and parent */
  GST_OBJECT_LOCK (pad);
  GST_CAT_INFO_OBJECT (GST_CAT_ELEMENT_PADS, element, "removing pad '%s'",
      GST_STR_NULL (GST_PAD_NAME (pad)));
  // 检查pad是否属于该元素
  if (G_UNLIKELY (GST_PAD_PARENT (pad) != element))
    goto not_our_pad;
  GST_OBJECT_UNLOCK (pad);

  /* unlink */
  // 如果pad有对等pad,需要先解锁连
  if ((peer = gst_pad_get_peer (pad))) {
    /* window for MT unsafeness, someone else could unlink here
     * and then we call unlink with wrong pads. The unlink
     * function would catch this and safely return failed. */
    if (GST_PAD_IS_SRC (pad))
      gst_pad_unlink (pad, peer);
    else
      gst_pad_unlink (peer, pad);

    gst_object_unref (peer);
  }

  /* if this is a ghost pad we also need to unset the target or it
   * will stay linked although not allowed according to the topology.
   *
   * FIXME 2.0: Do this generically somehow from inside GstGhostPad
   * when it gets unparented.
   */
  // 如果pad是一个ghost pad,清除其目标pad
  if (GST_IS_GHOST_PAD (pad)) {
    gst_ghost_pad_set_target (GST_GHOST_PAD (pad), NULL);
  }

  GST_OBJECT_LOCK (element);
  /* remove it from the list */
  // 从对应链表中删除
  switch (gst_pad_get_direction (pad)) {
    case GST_PAD_SRC:
      element->srcpads = g_list_remove (element->srcpads, pad);
      element->numsrcpads--;
      break;
    case GST_PAD_SINK:
      element->sinkpads = g_list_remove (element->sinkpads, pad);
      element->numsinkpads--;
      break;
    default:
      g_critical ("Removing pad without direction???");
      break;
  }
  element->pads = g_list_remove (element->pads, pad);
  element->numpads--;
  element->pads_cookie++;
  GST_OBJECT_UNLOCK (element);

  /* emit the PAD_REMOVED signal before unparenting and losing the last ref. */
  // 触发PAD_REMOVED信号,通知其他部分pad已被移除
  g_signal_emit (element, gst_element_signals[PAD_REMOVED], 0, pad);
  GST_TRACER_ELEMENT_REMOVE_PAD (element, pad);
  gst_object_unparent (GST_OBJECT_CAST (pad));

  return TRUE;

  /* ERRORS */
not_our_pad:
  {
    /* locking order is element > pad */
    GST_OBJECT_UNLOCK (pad);

    GST_OBJECT_LOCK (element);
    GST_OBJECT_LOCK (pad);
    g_critical ("Padname %s:%s does not belong to element %s when removing",
        GST_DEBUG_PAD_NAME (pad), GST_ELEMENT_NAME (element));
    GST_OBJECT_UNLOCK (pad);
    GST_OBJECT_UNLOCK (element);
    return FALSE;
  }
}

(3)gst_element_no_more_pads()
不期望在element中添加新的pads

void
gst_element_no_more_pads (GstElement * element)
{
  g_return_if_fail (GST_IS_ELEMENT (element));
  // 发布信号,元素不再添加新的pads
  g_signal_emit (element, gst_element_signals[NO_MORE_PADS], 0);
}

2.3 element的默认操作

(1)gst_element_constructed
构造element

static void
gst_element_constructed (GObject * object)
{
  GST_TRACER_ELEMENT_NEW (GST_ELEMENT_CAST (object));
  G_OBJECT_CLASS (parent_class)->constructed (object);
}

(2)gst_element_dispose
GstElement类的对象销毁方法,用于在元素被销毁时释放其引用,通常会在对象的引用计数降为0时调用

static void
gst_element_dispose (GObject * object)
{
  GstElement *element = GST_ELEMENT_CAST (object);
  GstClock **clock_p;
  GstBus **bus_p;
  GstElementClass *oclass;
  GList *walk;

  oclass = GST_ELEMENT_GET_CLASS (element);

  GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "%p dispose", element);
  // 检查element的状态
  if (GST_STATE (element) != GST_STATE_NULL)
    goto not_null;

  /* start by releasing all request pads, this might also remove some dynamic
   * pads */
  // 遍历element中的pads
  walk = element->pads;
  while (walk) {
    GstPad *pad = GST_PAD_CAST (walk->data);

    walk = walk->next;

    if (oclass->release_pad && GST_PAD_PAD_TEMPLATE (pad) &&
        GST_PAD_TEMPLATE_PRESENCE (GST_PAD_PAD_TEMPLATE (pad))
        == GST_PAD_REQUEST) {
      GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element,
          "removing request pad %s:%s", GST_DEBUG_PAD_NAME (pad));
      // 释放pad
      oclass->release_pad (element, pad);

      /* in case the release_pad function removed the next pad too */
      if (walk && g_list_position (element->pads, walk) == -1)
        walk = element->pads;
    }
  }
  /* remove the remaining pads */
  // 清理剩余没有清理完的pads
  while (element->pads) {
    GstPad *pad = GST_PAD_CAST (element->pads->data);
    GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element,
        "removing pad %s:%s", GST_DEBUG_PAD_NAME (pad));
    if (!gst_element_remove_pad (element, pad)) {
      /* only happens when someone unparented our pad.. */
      g_critical ("failed to remove pad %s:%s", GST_DEBUG_PAD_NAME (pad));
      break;
    }
  }

  GST_OBJECT_LOCK (element);
  clock_p = &element->clock;
  bus_p = &element->bus;
  // 将clock和bus设置为NULL
  gst_object_replace ((GstObject **) clock_p, NULL);
  gst_object_replace ((GstObject **) bus_p, NULL);
  // 清理上下文
  g_list_free_full (element->contexts, (GDestroyNotify) gst_context_unref);
  element->contexts = NULL;
  GST_OBJECT_UNLOCK (element);

  GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "%p parent class dispose",
      element);

  G_OBJECT_CLASS (parent_class)->dispose (object);

  return;

  /* ERRORS */
not_null:
  {
    gboolean is_locked;

    is_locked = GST_ELEMENT_IS_LOCKED_STATE (element);
    g_critical
        ("\nTrying to dispose element %s, but it is in %s%s instead of the NULL"
        " state.\n"
        "You need to explicitly set elements to the NULL state before\n"
        "dropping the final reference, to allow them to clean up.\n"
        "This problem may also be caused by a refcounting bug in the\n"
        "application or some element.\n",
        GST_OBJECT_NAME (element),
        gst_element_state_get_name (GST_STATE (element)),
        is_locked ? " (locked)" : "");
    return;
  }
}

(3)gst_element_finalize
finalize用于释放对象所占用的所有资源,例如内存、文件句柄等,只会被调用一次

static void
gst_element_finalize (GObject * object)
{
  GstElement *element = GST_ELEMENT_CAST (object);

  GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "%p finalize", element);
  // 清理状态信号
  g_cond_clear (&element->state_cond);
  // 清理状态锁
  g_rec_mutex_clear (&element->state_lock);

  GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "%p finalize parent",
      element);

  G_OBJECT_CLASS (parent_class)->finalize (object);
}

(4)gst_element_change_state_func
状态转换函数

/* is called with STATE_LOCK */
static GstStateChangeReturn
gst_element_change_state_func (GstElement * element, GstStateChange transition)
{
  GstState state, next;
  GstStateChangeReturn result = GST_STATE_CHANGE_SUCCESS;

  g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_CHANGE_FAILURE);
  // 获取当前状态和下一个状态
  state = (GstState) GST_STATE_TRANSITION_CURRENT (transition);
  next = GST_STATE_TRANSITION_NEXT (transition);

  /* if the element already is in the given state, we just return success */
  // 如果下一个状态为pending,或者当前状态与下一个状态一致,不需要修改状态
  if (next == GST_STATE_VOID_PENDING || state == next)
    goto was_ok;

  GST_CAT_LOG_OBJECT (GST_CAT_STATES, element,
      "default handler tries setting state from %s to %s (%04x)",
      gst_element_state_get_name (state),
      gst_element_state_get_name (next), transition);
  // 检查状态转换情况
  switch (transition) {
    case GST_STATE_CHANGE_NULL_TO_READY:
      break;
    case GST_STATE_CHANGE_READY_TO_PAUSED: 
      // gstreamer中的状态变换,从null -> ready -> paused -> playing
      // 从ready到paused,需要激活pads,表示元素已准备好处理数据,但不会主动推送数据
      if (!gst_element_pads_activate (element, TRUE)) {
        result = GST_STATE_CHANGE_FAILURE;
      }
      break;
    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
      break;
    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
      break;
    case GST_STATE_CHANGE_PAUSED_TO_READY:
    case GST_STATE_CHANGE_READY_TO_NULL:{
      GList *l;

      /* deactivate pads in both cases, since they are activated on
         ready->paused but the element might not have made it to paused */
      // 将pads设置为FALSE,表示不再接收数据
      if (!gst_element_pads_activate (element, FALSE)) {
        result = GST_STATE_CHANGE_FAILURE;
      }

      /* Remove all non-persistent contexts */
      // 移除所有非持久的上下文
      GST_OBJECT_LOCK (element);
      for (l = element->contexts; l;) {
        GstContext *context = l->data;

        if (!gst_context_is_persistent (context)) {
          GList *next;

          gst_context_unref (context);
          next = l->next;
          element->contexts = g_list_delete_link (element->contexts, l);
          l = next;
        } else {
          l = l->next;
        }
      }
      GST_OBJECT_UNLOCK (element);
      break;
    }
    default:
      /* this will catch real but unhandled state changes;
       * can only be caused by:
       * - a new state was added
       * - somehow the element was asked to jump across an intermediate state
       */
      g_warning ("Unhandled state change from %s to %s",
          gst_element_state_get_name (state),
          gst_element_state_get_name (next));
      break;
  }
  return result;

was_ok:
  {
    GST_OBJECT_LOCK (element);
    result = GST_STATE_RETURN (element);
    GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
        "element is already in the %s state",
        gst_element_state_get_name (state));
    GST_OBJECT_UNLOCK (element);

    return result;
  }
}

(5)gst_element_query
处理元素的查询操作,可以查询流的持续事件、查询支持的格式、请求定位操作等

gboolean
gst_element_query (GstElement * element, GstQuery * query)
{
  GstElementClass *klass;
  gboolean res = FALSE;

  g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
  g_return_val_if_fail (query != NULL, FALSE);

  GST_TRACER_ELEMENT_QUERY_PRE (element, query);

  klass = GST_ELEMENT_GET_CLASS (element);
  if (klass->query) {
    GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "send query on element %s",
        GST_ELEMENT_NAME (element));
    // 发送问询
    res = klass->query (element, query);
  }

  GST_TRACER_ELEMENT_QUERY_POST (element, query, res);
  return res;
}

(6)gst_element_send_event
向元素发送事件,事件用于在管道pipeline中传递控制信息或通知,例如事件可以用于执行定位操作、发送EOS信号、处理流的重构等

gboolean
gst_element_send_event (GstElement * element, GstEvent * event)
{
  GstElementClass *oclass;
  gboolean result = FALSE;

  g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
  g_return_val_if_fail (event != NULL, FALSE);

  oclass = GST_ELEMENT_GET_CLASS (element);

  GST_STATE_LOCK (element);
  if (oclass->send_event) {
    GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "send %s event on element %s",
        GST_EVENT_TYPE_NAME (event), GST_ELEMENT_NAME (element));
    // 发送事件
    result = oclass->send_event (element, event);
  } else {
    gst_event_unref (event);
  }
  GST_STATE_UNLOCK (element);

  return result;
}

(7)gst_element_post_message
将消息发布到元素的总线。这个函数可以将元素消息传递给应用程序,应用程序可以通过监听总线来接收这些消息

gboolean
gst_element_post_message (GstElement * element, GstMessage * message)
{
  GstElementClass *klass;
  gboolean res = FALSE;

  g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
  g_return_val_if_fail (message != NULL, FALSE);

  GST_TRACER_ELEMENT_POST_MESSAGE_PRE (element, message);

  klass = GST_ELEMENT_GET_CLASS (element);
  if (klass->post_message) // 发布消息到总线
    res = klass->post_message (element, message);
  else
    gst_message_unref (message);

  GST_TRACER_ELEMENT_POST_MESSAGE_POST (element, res);
  return res;
}

在上面的函数中,使用了许多的函数指针,例如klass->post_message(),这些函数的赋值在各自的element中给出

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值