Gstreamer初见

http://blog.csdn.net/maeom/article/details/7693520    


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

    系统: meego-1.2

    应用: Qt + Gstreamer

    应用使用的Gstreamer playbin2 控件。 

  

  (1) 概述

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

[cpp]  view plain copy
  1. +-------------------------------------+  
  2. |            ELEMENT                  |  
  3. |--------------+              +-------|  
  4. |sinkpad       |              |       |  
  5. |  +---------+ |              |       |  
  6. |  | caps    | |              |srcpad |  
  7. |  | caps    | |              |       |  
  8. |  +---------+ |              |       |  
  9. |--------------+              +-------|  
  10. +-------------------------------------+  
        这里列举实例如:qtdemux (quicktime demux)

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

[cpp]  view plain copy
  1. static GstStaticPadTemplate gst_qtdemux_sink_template =  
  2.     GST_STATIC_PAD_TEMPLATE ("sink",  
  3.     GST_PAD_SINK,  
  4.     GST_PAD_ALWAYS,  
  5.     GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "  
  6.         "application/x-3gp")  
  7.     );  
  8.   
  9. static void  
  10. gst_qtdemux_init (GstQTDemux * qtdemux, GstQTDemuxClass * klass)  
  11. {  
  12.   qtdemux->sinkpad =  
  13.     gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");  
  14.   gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);  
  15. }  
  16.   
  17. static gboolean  
  18. qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)  
  19. {  
  20.   stream->caps =  
  21.     qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);  
  22.   
  23.   qtdemux->streams[qtdemux->n_streams] = stream;  
  24. }  
    (1.2) playbin内部
[cpp]  view plain copy
  1. +------------------------------------------------------------+  
  2. |            playbin2                                        |  
  3. | +---------------------------------------------------+      |  
  4. | |uridecodebin                                       |      |  
  5. | |  +----------+     +----------+     +-----------+  |      |  
  6. | |  | typefind |     |  queue2  |     | decodebin |  |      |  
  7. | |->|          |>--->|          |>--->|           |> |      |  
  8. | |  |          |     |          |     |           |  |      |  
  9. | |  +----------+     +----------+     +-----------+  |      |  
  10. | +---------------------------------------------------+      |  
  11. +------------------------------------------------------------+  

  (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 对比

[cpp]  view plain copy
  1. gboolean  
  2. gst_element_link_pads (GstElement * src, const gchar * srcpadname,  
  3.     GstElement * dest, const gchar * destpadname)  
  4. {  
  5.   return gst_element_link_pads_full (src, srcpadname, dest, destpadname,  
  6.       GST_PAD_LINK_CHECK_DEFAULT);  
  7. }  
  8.   
  9. gboolean  
  10. gst_element_link_pads_full (GstElement * src, const gchar * srcpadname,  
  11.     GstElement * dest, const gchar * destpadname, GstPadLinkCheck flags)  
  12. {  
  13.   result = pad_link_maybe_ghosting (srcpad, destpad, flags);  
  14. }  
  15.   
  16. static gboolean  
  17. pad_link_maybe_ghosting (GstPad * src, GstPad * sink, GstPadLinkCheck flags)  
  18. {  
  19.   ret = (gst_pad_link_full (src, sink, flags) == GST_PAD_LINK_OK);  
  20. }  
  21.   
  22. /* 和 gst_pad_link 一样 */  
  23. GstPadLinkReturn  
  24. gst_pad_link (GstPad * srcpad, GstPad * sinkpad)  
  25. {  
  26.   return gst_pad_link_full (srcpad, sinkpad, GST_PAD_LINK_CHECK_DEFAULT);  
  27. }  
        (2.2) pad link 到底做什么了?原来就是互相将peer设置为对端

[cpp]  view plain copy
  1. GstPadLinkReturn  
  2. gst_pad_link_full (GstPad * srcpad, GstPad * sinkpad, GstPadLinkCheck flags)  
  3. {  
  4.   /* 这个参考 GstPad 的 structure, 这里就是互相将peer设置为对端 */  
  5.   GST_PAD_PEER (srcpad) = sinkpad;  
  6.   GST_PAD_PEER (sinkpad) = srcpad;  
  7.   
  8.   /* 如果有link func那么执行函数,大部分element中没有设置link func函数 */  
  9.   if (GST_PAD_LINKFUNC (srcpad)) {  
  10.     result = GST_PAD_LINKFUNC (srcpad) (srcpad, sinkpad);  
  11.   } else if (GST_PAD_LINKFUNC (sinkpad)) {  
  12.     result = GST_PAD_LINKFUNC (sinkpad) (sinkpad, srcpad);  
  13.   } else {  
  14.     result = GST_PAD_LINK_OK;  
  15.   }  
  16. }  

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

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

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

[cpp]  view plain copy
  1. /* gstreamer-0.10.32/plugins/elements/gstqueue2.c */  
  2. static void  
  3. gst_queue2_init (GstQueue2 * queue, GstQueue2Class * g_class)  
  4. {  
  5.   /*创建sinkpad*/  
  6.   queue->sinkpad = gst_pad_new_from_static_template (&sinktemplate, "sink");  
  7.   
  8.   /* 设置sinkpad的chain function, 这个函数后面会用到, 也是sinkpad数据的入口*/  
  9.   gst_pad_set_chain_function (queue->sinkpad,  
  10.       GST_DEBUG_FUNCPTR (gst_queue2_chain));  
  11.   
  12.   queue->srcpad = gst_pad_new_from_static_template (&srctemplate, "src");  
  13.   
  14.   /* 这里是用srcpad开始向外推送数据 */  
  15.   gst_pad_set_activatepush_function (queue->srcpad,  
  16.       GST_DEBUG_FUNCPTR (gst_queue2_src_activate_push));  
  17. }  
  18.   
  19. /*我们从chain function开始看,为什么chain function是入口函数? 往下看*/  
  20. static GstFlowReturn  
  21. gst_queue2_chain (GstPad * pad, GstBuffer * buffer)  
  22. {  
  23.   gst_queue2_locked_enqueue (queue, buffer, TRUE);   
  24. }  
  25.   
  26. static void  
  27. gst_queue2_locked_enqueue (GstQueue2 * queue, gpointer item, gboolean isbuffer)  
  28. {  
  29.   if (isbuffer) {  
  30.     if (QUEUE_IS_USING_QUEUE (queue)) {  
  31.       queue->cur_level.buffers++;  
  32.     }  
  33.   } else if (GST_IS_EVENT (item)) {  
  34.   }  
  35.     
  36.   if (item) {  
  37.      if (QUEUE_IS_USING_QUEUE (queue)) {  
  38.          /* 这里把buffer放在queue里 */  
  39.         g_queue_push_tail (queue->queue, item);  
  40.      }  
  41.   }  
  42. }  
  43.   
  44. /* 接收数据完成了,下面看srcpad向外推送数据 */  
  45. static gboolean  
  46. gst_queue2_src_activate_push (GstPad * pad, gboolean active)  
  47. {  
  48.   if (active) {  
  49.     result = gst_pad_start_task (pad, (GstTaskFunction) gst_queue2_loop, pad);  
  50.   }  
  51. }  
  52.   
  53. static void  
  54. gst_queue2_loop (GstPad * pad)  
  55. {  
  56.   ret = gst_queue2_push_one (queue);  
  57. }  
  58.   
  59. static GstFlowReturn  
  60. gst_queue2_push_one (GstQueue2 * queue)  
  61. {  
  62.   data = gst_queue2_locked_dequeue (queue, &is_buffer);  
  63.   if (is_buffer) {  
  64.     /* 发送数据 */  
  65.     result = gst_pad_push (queue->srcpad, buffer);  
  66.   } else if (GST_IS_EVENT (data)) {  
  67.     /* 这里是发送事件,会获取srcpad的peerpad,然后调用eventfunc,原理与发送数据类似 */  
  68.     gst_pad_push_event (queue->srcpad, event);  
  69.   }  
  70. }  
  71.   
  72. /* gstreamer/gst/gstpad.c */  
  73. GstFlowReturn  
  74. gst_pad_push (GstPad * pad, GstBuffer * buffer)  
  75. {  
  76.   /* 这个看起来很复杂,... 初一见,都觉得头疼,这么多层。 
  77.    * 实际上并不复杂,他的作用就是,此前如果该gstpad,有过push操作,并建立好了路径,那么直接使用, 
  78.    * 否则跳到slow_path执行。 
  79.    */  
  80.   cache_ptr = (gpointer *) & pad->abidata.ABI.priv->cache_ptr;  
  81.     
  82.   cache = pad_take_cache (pad, cache_ptr);  
  83.   
  84.   if (G_UNLIKELY (cache == NULL))  
  85.     goto slow_path;  
  86.   
  87.   peer = cache->peer;  
  88.     
  89.   ret = GST_PAD_CHAINFUNC (peer) (peer, buffer);  
  90.   return ret;  
  91.   
  92. slow_path:  
  93.   GstPadPushCache scache = { NULL, };  
  94.   /* 实际上这里面一样是调用了srcpad的peer端的chain_func [注:与我们开始从chain_func分析吻合] */  
  95.   ret = gst_pad_push_data (pad, TRUE, buffer, &scache);   
  96.     
  97.   if (scache.peer) {  
  98.     /* 这里就将cache_ptr 赋值到pad->abidata.ABI.priv->cache_ptr 这么长的里面了 */  
  99.     pad_put_cache (pad, ncache, cache_ptr);  
  100.   }  
  101. }  
  102.   
  103. /* 贯彻到底,我们将srcpad最后的调用对端的chainfunc挖出来 */  
  104. static GstFlowReturn  
  105. gst_pad_push_data (GstPad * pad, gboolean is_buffer, void *data,  
  106.                    GstPadPushCache * cache)  
  107. {  
  108.   if (G_UNLIKELY ((peer = GST_PAD_PEER (pad)) == NULL))  
  109.     goto not_linked;  
  110.   
  111.   ret = gst_pad_chain_data_unchecked (peer, is_buffer, data, cache);   
  112. }  
  113.   
  114. static inline GstFlowReturn  
  115. gst_pad_chain_data_unchecked (GstPad * pad, gboolean is_buffer, void *data,  
  116.     GstPadPushCache * cache)  
  117. {  
  118.   if (G_LIKELY (is_buffer)) {  
  119.     if (G_UNLIKELY ((chainfunc = GST_PAD_CHAINFUNC (pad)) == NULL))  
  120.       goto no_function;  
  121.   
  122.     /* 这里调用了srcpad的peer端的 chainfunc 开始执行。 queue2的chainfunc一样的开始道理 */  
  123.     ret = chainfunc (pad, GST_BUFFER_CAST (data));  
  124.   }  
  125. }  

你可能感兴趣的:(Gstreamer初见)