gstreamer的collectpad源码分析

本文深入分析了GStreamer中collectpad的工作原理,它用于管理合成器的数据同步。collectpad采用可重载的处理函数,当pad数据到达时,依据收集条件判断数据处理。文章探讨了默认流程、数据结构,特别是异常流程,包括非等待状态可能导致的死循环和过度弹出buffer问题。此外,还讲解了寻找最早时间点buffer的逻辑及锁和等待状态的管理。
摘要由CSDN通过智能技术生成
1. 背景:

        gstreamer的collectpad是一类特殊的pad,这类pad工作于收集模式,用于管理控制若干个pad组成的pad集合的数据同步处理。大部分的合成器(muxer)均使用collectpad来收集音视频数据,并根据可重载的收集条件判断函数对不同pad之间的数据进行处理(或同步)。

        由于collectpad中大部分处理函数均可重载(set_func),因此本文只讨论默认的处理函数。

2. 默认流程:

        collectpad的简单流程如下图:


        不同的pad工作与不同的线程中,当某一个pad有数据到来时,会对所有pad进行判断,看看是否可以满足收集条件,如果满足收集条件就向对应的element推送数据。如果不满足收集条件,就会将该线程挂起,等待其他线程的数据。

        当某个pad处于挂起时,其他pad收到数据后,一样会对收集条件进行判断,如果满足条件,会将所有pad的数据推送至element,同时广播条件变量,唤醒所有挂起中的其他pad(线程)。

        简单的函数调用关系如下:


3. 数据结构:

        数据结构如下:一个_GstCollectPads中维护了一个_GstCollectData的链表,每个pad对应一个_GstCollectData,其中记录了pad中的数据的时间戳,buffer,已经对应pad的状态(如锁、等待等标志位),GstCollectPadsPrivate中则记录了collectpad中注册的各种事件回调函数,这里的回调函数都有接口可以进行重载。此外,GstCollectPadsPrivate还维护了线程间同步用的锁和条件变量。

/**
 * GstCollectPads:
 * @data: (element-type GstBase.CollectData): #GList of #GstCollectData managed
 *   by this #GstCollectPads.
 *
 * Collectpads object.
 */
struct _GstCollectPads {
  /* 基类。  */
  GstObject      object;

  /*< public >*/ /* with LOCK and/or STREAM_LOCK */
  /* 所有PAD的集合。  */
  /*
    * GstCollectData:
    * @collect: owner #GstCollectPads
    * @pad: #GstPad managed by this data
    * @buffer: currently queued buffer.
    * @pos: position in the buffer
    * @segment: last segment received.
    * @dts: the signed version of the DTS converted to running time. To access
    *       this memeber, use %GST_COLLECT_PADS_DTS macro. (Since 1.6)
    *
    * Structure used by the collect_pads.
    struct _GstCollectData
    {
      /* with STREAM_LOCK of @collect */
      /* 指向回collectpad。  */
      GstCollectPads        *collect;
      GstPad                *pad;
      GstBuffer             *buffer;
      guint                  pos;
      GstSegment             segment;
    
      /*< private >*/
      /* state: bitfield for easier extension;
       * eos, flushing, new_segment, waiting */
      GstCollectPadsStateFlags    state;
    
      GstCollectDataPrivate *priv;
    
      union {
        struct {
          /*< public >*/
          gint64 dts;
          /*< private >*/
        } abi;
        gpointer _gst_reserved[GST_PADDING];
      } ABI;
    };
   */
  GSList        *data;                  /* list of CollectData items */

  /*< private >*/
  GRecMutex      stream_lock;          /* used to serialize collection among several streams */

  GstCollectPadsPrivate *priv;

  gpointer _gst_reserved[GST_PADDING];
};

4. 代码分析:

4.1 主入口函数:

        主入口函数gst_collect_pads_chain,不同pad工作于不同线程中。代码分析如下:

/* For each buffer we receive we check if our collected condition is reached
 * and if so we call the collected function. When this is done we check if
 * data has been unqueued. If data is still queued we wait holding the stream
 * lock to make sure no EOS event can happen while we are ready to be
 * collected 
 */
static GstFlowReturn
gst_collect_pads_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
{
  GstCollectData *data;
  GstCollectPads *pads;
  GstFlowReturn ret;
  GstBuffer **buffer_p;
  guint32 cookie;

  GST_DEBUG ("Got buffer for pad %s:%s", GST_DEBUG_PAD_NAME (pad));

  /* some magic to get the managing collect_pads */
  GST_OBJECT_LOCK (pad);
  data = (GstCollectData *) gst_pad_get_element_private (pad);
  if (G_UNLIKELY (data == NULL))
    goto no_data;
  ref_data (data);
  GST_OBJECT_UNLOCK (pad);

  pads = data->collect;

  GST_COLLECT_PADS_STREAM_LOCK (pads);
  /* 状态判断。  */
  /* if not started, bail out */
  if (G_UNLIKELY (!pads->priv->started))
    goto not_started;
  /* check if this pad is flushing */
  if (G_UNLIKELY (GST_COLLECT_PADS_STATE_IS_SET (data,
              GST_COLLECT_PADS_STATE_FLUSHING)))
    goto flushing;
  /* pad was EOS, we can refuse this data */
  if (G_UNLIKELY (GST_COLLECT_PADS_STATE_IS_SET (data,
              GST_COLLECT_PADS_STATE_EOS)))
    goto eos;

  /* see if we need to clip */
  /* 数据前处理。  */
  if (pads->priv->clip_func) {
    GstBuffer *outbuf = NULL;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值