Gstreamer动态插件的实现与原理

原文:http://blog.chinaunix.net/uid-24922718-id-3267099.html


gstremer的插件机制是其核心,所有的元件的都是以插件的形式绑定在管道中用来实现媒体播放的效果。动态加 载机制简单的说就是gstreamer框架依照所请求的流的格式来向自己的插件库中寻找可用插件已实现自动绑定的一种模式。这大大方便了对于上层应用开发人员的使用。

    decodebin2就是动态加载机制实现的一个解码管道,根据手册上说的可以知道,动态加载核心便是在管道中加载了一个typefind的插件,该插件就是实现对于所注册插件的查找功能,那我们就先来看下decodebin2中是如何使用typefind插件的。
   在decodebin2的源码文件中我们可以到到,在初始话decodebin2管道的过程中,添加了一个typefind的插件,并为这个插件注册了信号have -type  ,当有数据流流过这个typefind时,会出发并发送have-type信号,链接到相应的回调函数后,会对数据的mime/type进行检查(mime/type的详细注册及有关有关问题在下一期中会进行分析),在type-found信号回调函数中判断流的格式,如果是text/plain形式,就不进行处理,否则就获取该文件的mime /type。
  1. /* If the typefinder (but not something else) finds text/plain- i.e. that's
  2.    * the top-level type of the file- then error out.
  3.    */
  4.   if (gst_structure_has_name(gst_caps_get_structure (caps, 0),"text/plain")){
  5.     GST_ELEMENT_ERROR (decode_bin, STREAM, WRONG_TYPE,
  6.         (_("This appears to be a text file")),
  7.         ("decodebin2 cannot decode plain text files"));
  8.     goto exit;
  9.   }

  10.   /* FIXME: we can only deal with one type, we don't yet support dynamically changing
  11.    * caps from the typefind element */
  12.   if (decode_bin->have_type|| decode_bin->decode_chain)
  13.     goto exit;
获取后,对与typefind的srcpad进行设定,在analyze_new_pad函数中,为typefind添加了srcpad后,发送了Autoplug-continue信号,以进行动态加载,那又是如何实现动态加载的呢?
    在该函数中,会发送信号signal-autopluf_factory信号
  1. /* 1.delse get the factoriesand if there's no compatible factory goto
  2.    * unknown_type */
  3.   g_signal_emit (G_OBJECT (dbin),
  4.       gst_decode_bin_signals[SIGNAL_AUTOPLUG_FACTORIES], 0, dpad, caps,
  5.       &factories);
发送后,进入这个信号的执行函数中,发现调用了gst_element_factory_list_filter,通过执行这个函数后,得到满足caps的可能元件的工厂列表,然后从中选择出最合适的元件。
   那从什么类行的工厂中选择的呢?这就是实现动态加载机制的关键所在了,我们接下去往下看
  1. static GValueArray *
  2. gst_decode_bin_autoplug_factories (GstElement* element, GstPad* pad,
  3.     GstCaps * caps)
  4. {
  5.   GList *list,*tmp;
  6.   GValueArray *result;
  7.   GstDecodeBin *dbin = GST_DECODE_BIN_CAST (element);

  8.   GST_DEBUG_OBJECT (element,"finding factories");

  9.   /* return all compatible factoriesfor caps */
  10.   g_mutex_lock (dbin->factories_lock);
  11.   gst_decode_bin_update_factories_list (dbin);
  12.   list =
  13.       gst_element_factory_list_filter (dbin->factories, caps, GST_PAD_SINK,
  14.       FALSE);
  15.   g_mutex_unlock (dbin->factories_lock);

  16.   result = g_value_array_new (g_list_length (list));
  17.   for (tmp= list; tmp; tmp= tmp->next){
  18.     GstElementFactory *factory = GST_ELEMENT_FACTORY_CAST (tmp->data);
  19.     GValue val = { 0, };

  20.     g_value_init (&val, G_TYPE_OBJECT);
  21.     g_value_set_object (&val, factory);
  22.     g_value_array_append (result,&val);
  23.     g_value_unset (&val);
  24.   }
  25.   gst_plugin_feature_list_free (list);

  26.   GST_DEBUG_OBJECT (element,"autoplug-factories returns %p", result);

  27.   return result;
  28. }

代码通过update-factories_list,然后进入gst_element_factory_list_get_element,这下发现了,这个函数的两个参数貌似是决定最后选择什么工厂类型的罪魁祸首,那我们看下要如何定义自己的插件已来满足这两个要求。
   第一个参数是GST_ELEMENT_FACTORY_TYPE_DECODEABLE
   查找了下这个参数,发现在源码中有这样的定义
  1. #define GST_ELEMENT_FACTORY_TYPE_DECODABLE \
  2.   (GST_ELEMENT_FACTORY_TYPE_DECODER | GST_ELEMENT_FACTORY_TYPE_DEMUXER | GST_ELEMENT_FACTORY_TYPE_DEPAYLOADER| GST_ELEMENT_FACTORY_TYPE_PARSER)

  3. /* Element klass defines */
  4. #define GST_ELEMENT_FACTORY_KLASS_DECODER        "Decoder"
  5. #define GST_ELEMENT_FACTORY_KLASS_ENCODER        "Encoder"
  6. #define GST_ELEMENT_FACTORY_KLASS_SINK            "Sink"
  7. #define GST_ELEMENT_FACTORY_KLASS_SRC            "Source"
  8. #define GST_ELEMENT_FACTORY_KLASS_MUXER            "Muxer"
  9. #define GST_ELEMENT_FACTORY_KLASS_DEMUXER        "Demuxer"
  10. #define GST_ELEMENT_FACTORY_KLASS_PARSER        "Parser"
  11. #define GST_ELEMENT_FACTORY_KLASS_PAYLOADER        "Payloader"
  12. #define GST_ELEMENT_FACTORY_KLASS_DEPAYLOADER        "Depayloader"
  13. #define GST_ELEMENT_FACTORY_KLASS_FORMATTER        "Formatter"

  14. #define GST_ELEMENT_FACTORY_KLASS_MEDIA_VIDEO        "Video"
  15. #define GST_ELEMENT_FACTORY_KLASS_MEDIA_AUDIO        "Audio"
  16. #define GST_ELEMENT_FACTORY_KLASS_MEDIA_IMAGE        "Image"
  17. #define GST_ELEMENT_FACTORY_KLASS_MEDIA_SUBTITLE    "Subtitle"
  18. #define GST_ELEMENT_FACTORY_KLASS_MEDIA_METADATA    "Metadata"
是不是感觉下面的这些宏本体有些熟悉?用inspect打开一个插件的定义,找下,发现果然是class属性字段有这类的定义,那是不是这个就是始作俑者呢?在往下看,进入gst_element_factory_list_get_elements中,给定参数后,在进入registry_feature_filter函数,发现这个函数的本体是gst_registry_feature_filter,注意到,最终,rank和TYPE还是给了gselementfactory.c文件中的element_filter,进行选择元件的过滤工作,在该函数中进行了类型rank的比较,即rank必须大于所只制定的等级,以及类型要相仿
再看类型鉴定函数gst_element_factory_list_is_type函数,从这个函数中可以看出除了sink,src类型外,只要满足后面的一种类型,该插件就可以放到返回的工厂列表中,以后以后对于mime/type的匹配选择动态加载合适的插件。


说了那么多,总结起来就是:decodebin通过typefind查找合适的插件进行动态绑定,它是从满足DECODEBLE类型的插件工厂中,找出合适的mimetype类型以实现动态加载,所以,对于我们要做的demux类插件,只需要在生成了插件模板后,对于插件的等级,和class属性进行以上分析的设定便可。

你可能感兴趣的:(Gstreamer)