Gstreamer初见

来源:互联网 发布:毒品网络 电影 编辑:程序博客网 时间:2024/06/11 18:05

    项目相关:网络视频播放器

    系统: meego-1.2

    应用: Qt + Gstreamer

    应用使用的Gstreamer playbin2 控件。

 

  (1) 概述

        (1.1)  Element, Pad, Caps 之间的关系。

             +-------------------------------------+             |            ELEMENT                  |             |--------------+              +-------|             |sinkpad       |              |       |             |  +---------+ |              |       |             |  | caps    | |              |srcpad |             |  | caps    | |              |       |             |  +---------+ |              |       |             |--------------+              +-------|             +-------------------------------------+
        这里列举实例如:qtdemux (quicktime demux)

        这里简单列出,详细部分参考源码:gst-plugins-good-0.10.27/gst/qtdemux/qtdemux.c   

static GstStaticPadTemplate gst_qtdemux_sink_template =    GST_STATIC_PAD_TEMPLATE ("sink",    GST_PAD_SINK,    GST_PAD_ALWAYS,    GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "        "application/x-3gp")    );static voidgst_qtdemux_init (GstQTDemux * qtdemux, GstQTDemuxClass * klass){  qtdemux->sinkpad =    gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");  gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);}static gbooleanqtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak){  stream->caps =    qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);  qtdemux->streams[qtdemux->n_streams] = stream;}
    (1.2) playbin内部
             +------------------------------------------------------------+             |            playbin2                                        |             | +---------------------------------------------------+      |             | |uridecodebin                                       |      |             | |  +----------+     +----------+     +-----------+  |      |             | |  | typefind |     |  queue2  |     | decodebin |  |      |             | |->|          |>--->|          |>--->|           |> |      |             | |  |          |     |          |     |           |  |      |             | |  +----------+     +----------+     +-----------+  |      |             | +---------------------------------------------------+      |             +------------------------------------------------------------+

  (2)  链接(link)

    gstreamer中,element, pad 都是通过gst_element_link_pads,  或gst_pad_link链接起来的。并且显然,pad嵌在element元件内部,当将两个element link起来时,真正发生的改变是什么呢?

       (2.1) gst_element_lin_pads 与 gst_pad_link 对比

gbooleangst_element_link_pads (GstElement * src, const gchar * srcpadname,    GstElement * dest, const gchar * destpadname){  return gst_element_link_pads_full (src, srcpadname, dest, destpadname,      GST_PAD_LINK_CHECK_DEFAULT);}gbooleangst_element_link_pads_full (GstElement * src, const gchar * srcpadname,    GstElement * dest, const gchar * destpadname, GstPadLinkCheck flags){  result = pad_link_maybe_ghosting (srcpad, destpad, flags);}static gbooleanpad_link_maybe_ghosting (GstPad * src, GstPad * sink, GstPadLinkCheck flags){  ret = (gst_pad_link_full (src, sink, flags) == GST_PAD_LINK_OK);}/* 和 gst_pad_link 一样 */GstPadLinkReturngst_pad_link (GstPad * srcpad, GstPad * sinkpad){  return gst_pad_link_full (srcpad, sinkpad, GST_PAD_LINK_CHECK_DEFAULT);}
        (2.2) pad link 到底做什么了?

GstPadLinkReturngst_pad_link_full (GstPad * srcpad, GstPad * sinkpad, GstPadLinkCheck flags){  /* 这个参考 GstPad 的 structure, 这里就是互相将peer设置为对端 */  GST_PAD_PEER (srcpad) = sinkpad;  GST_PAD_PEER (sinkpad) = srcpad;  /* 如果有link func那么执行函数,大部分element中没有设置link func函数 */  if (GST_PAD_LINKFUNC (srcpad)) {    result = GST_PAD_LINKFUNC (srcpad) (srcpad, sinkpad);  } else if (GST_PAD_LINKFUNC (sinkpad)) {    result = GST_PAD_LINKFUNC (sinkpad) (sinkpad, srcpad);  } else {    result = GST_PAD_LINK_OK;  }}

     这里就将两个element链接起来了,post message等操作,就可以发送消息,数据了

(3) 在element内/间,消息/数据是如何路径呢,下面我们分析下数据,事件原理与数据类似。

  以queue2为例子,看看如何从sinkpad收到消息,以及从srcpad发送到对端的sinkpad中。

/* gstreamer-0.10.32/plugins/elements/gstqueue2.c */static voidgst_queue2_init (GstQueue2 * queue, GstQueue2Class * g_class){  /*创建sinkpad*/  queue->sinkpad = gst_pad_new_from_static_template (&sinktemplate, "sink");  /* 设置sinkpad的chain function, 这个函数后面会用到, 也是sinkpad数据的入口*/  gst_pad_set_chain_function (queue->sinkpad,      GST_DEBUG_FUNCPTR (gst_queue2_chain));  queue->srcpad = gst_pad_new_from_static_template (&srctemplate, "src");  /* 这里是用srcpad开始向外推送数据 */  gst_pad_set_activatepush_function (queue->srcpad,      GST_DEBUG_FUNCPTR (gst_queue2_src_activate_push));}/*我们从chain function开始看,为什么chain function是入口函数? 往下看*/static GstFlowReturngst_queue2_chain (GstPad * pad, GstBuffer * buffer){  gst_queue2_locked_enqueue (queue, buffer, TRUE); }static voidgst_queue2_locked_enqueue (GstQueue2 * queue, gpointer item, gboolean isbuffer){  if (isbuffer) {    if (QUEUE_IS_USING_QUEUE (queue)) {      queue->cur_level.buffers++;    }  } else if (GST_IS_EVENT (item)) {  }    if (item) {     if (QUEUE_IS_USING_QUEUE (queue)) {         /* 这里把buffer放在queue里 */        g_queue_push_tail (queue->queue, item);     }  }}/* 接收数据完成了,下面看srcpad向外推送数据 */static gbooleangst_queue2_src_activate_push (GstPad * pad, gboolean active){  if (active) {    result = gst_pad_start_task (pad, (GstTaskFunction) gst_queue2_loop, pad);  }}static voidgst_queue2_loop (GstPad * pad){  ret = gst_queue2_push_one (queue);}static GstFlowReturngst_queue2_push_one (GstQueue2 * queue){  data = gst_queue2_locked_dequeue (queue, &is_buffer);  if (is_buffer) {    /* 发送数据 */    result = gst_pad_push (queue->srcpad, buffer);  } else if (GST_IS_EVENT (data)) {    /* 这里是发送事件,会获取srcpad的peerpad,然后调用eventfunc,原理与发送数据类似 */    gst_pad_push_event (queue->srcpad, event);  }}/* gstreamer/gst/gstpad.c */GstFlowReturngst_pad_push (GstPad * pad, GstBuffer * buffer){  /* 这个看起来很复杂,... 初一见,都觉得头疼,这么多层。   * 实际上并不复杂,他的作用就是,此前如果该gstpad,有过push操作,并建立好了路径,那么直接使用,   * 否则跳到slow_path执行。   */  cache_ptr = (gpointer *) & pad->abidata.ABI.priv->cache_ptr;    cache = pad_take_cache (pad, cache_ptr);  if (G_UNLIKELY (cache == NULL))    goto slow_path;  peer = cache->peer;    ret = GST_PAD_CHAINFUNC (peer) (peer, buffer);  return ret;slow_path:  GstPadPushCache scache = { NULL, };  /* 实际上这里面一样是调用了srcpad的peer端的chain_func [注:与我们开始从chain_func分析吻合] */  ret = gst_pad_push_data (pad, TRUE, buffer, &scache);     if (scache.peer) {    /* 这里就将cache_ptr 赋值到pad->abidata.ABI.priv->cache_ptr 这么长的里面了 */    pad_put_cache (pad, ncache, cache_ptr);  }}/* 贯彻到底,我们将srcpad最后的调用对端的chainfunc挖出来 */static GstFlowReturngst_pad_push_data (GstPad * pad, gboolean is_buffer, void *data,                   GstPadPushCache * cache){  if (G_UNLIKELY ((peer = GST_PAD_PEER (pad)) == NULL))    goto not_linked;  ret = gst_pad_chain_data_unchecked (peer, is_buffer, data, cache); }static inline GstFlowReturngst_pad_chain_data_unchecked (GstPad * pad, gboolean is_buffer, void *data,    GstPadPushCache * cache){  if (G_LIKELY (is_buffer)) {    if (G_UNLIKELY ((chainfunc = GST_PAD_CHAINFUNC (pad)) == NULL))      goto no_function;    /* 这里调用了srcpad的peer端的 chainfunc 开始执行。 queue2的chainfunc一样的开始道理 */    ret = chainfunc (pad, GST_BUFFER_CAST (data));  }}



原创粉丝点击