gstreamer教程系列之动态插件的实现与原理

 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.else get the factories and 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 factories for 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属性进行以上分析的设定便可。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现一个gstreamer编码插件,你需要遵循以下步骤: 1. 定义插件的元数据:在插件的源代码中定义元数据,如插件的名字、类型、作者、版本号等。 2. 实现插件的结构:定义插件的类和结构体,包括源代码文件、头文件、库文件和插件模板。 3. 实现插件的功能:在插件结构中定义编码器的功能,包括输入数据的格式、编码参数等。 4. 编译和安装插件:将插件源代码编译成共享库文件,并将其安装到gstreamer插件目录中。 以下是一个简单的gstreamer编码插件示例: ```c #include <gst/gst.h> #include <string.h> GST_DEBUG_CATEGORY_STATIC (myencoder_debug); #define GST_CAT_DEFAULT myencoder_debug #define GST_TYPE_MYENCODER \ (myencoder_get_type()) #define GST_MYENCODER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MYENCODER,MyEncoder)) #define GST_MYENCODER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MYENCODER,MyEncoderClass)) #define GST_IS_MYENCODER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MYENCODER)) #define GST_IS_MYENCODER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MYENCODER)) typedef struct _MyEncoder MyEncoder; typedef struct _MyEncoderClass MyEncoderClass; struct _MyEncoder { GstElement element; GstPad *sinkpad, *srcpad; gboolean silent; }; struct _MyEncoderClass { GstElementClass parent_class; }; GType myencoder_get_type (void); static void myencoder_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void myencoder_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static GstFlowReturn myencoder_chain (GstPad * pad, GstObject * parent, GstBuffer * buf); static gboolean myencoder_sink_event (GstPad * pad, GstObject * parent, GstEvent * event); static gboolean myencoder_src_event (GstPad * pad, GstObject * parent, GstEvent * event); static void myencoder_finalize (GObject * object); #define MYENCODER_PROP_SILENT 1 #define gst_myencoder_parent_class parent_class G_DEFINE_TYPE (MyEncoder, myencoder, GST_TYPE_ELEMENT); static void myencoder_class_init (MyEncoderClass * klass) { GObjectClass *gobject_class; GstElementClass *gstelement_class; gobject_class = (GObjectClass *) klass; gstelement_class = (GstElementClass *) klass; gobject_class->set_property = myencoder_set_property; gobject_class->get_property = myencoder_get_property; g_object_class_install_property (gobject_class, MYENCODER_PROP_SILENT, g_param_spec_boolean ("silent", "Silent", "Produce verbose output ?", FALSE, G_PARAM_READWRITE)); gstelement_class->sink_event = GST_DEBUG_FUNCPTR (myencoder_sink_event); gstelement_class->src_event = GST_DEBUG_FUNCPTR (myencoder_src_event); gstelement_class->finalize = GST_DEBUG_FUNCPTR (myencoder_finalize); gst_element_class_set_static_metadata (gstelement_class, "My Encoder", "Codec/Encoder", "Encode data using a custom algorithm", "Your Name <[email protected]>"); } static void myencoder_init (MyEncoder * filter) { filter->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink"); gst_pad_set_chain_function (filter->sinkpad, myencoder_chain); gst_pad_set_event_function (filter->sinkpad, GST_DEBUG_FUNCPTR (gst_pad_event_default)); GST_PAD_SET_PROXY_CAPS (filter->sinkpad); gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad); filter->srcpad = gst_pad_new_from_static_template (&src_template, "src"); gst_pad_use_fixed_caps (filter->srcpad); gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad); filter->silent = FALSE; } static void myencoder_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { MyEncoder *filter = GST_MYENCODER (object); switch (prop_id) { case MYENCODER_PROP_SILENT: filter->silent = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void myencoder_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { MyEncoder *filter = GST_MYENCODER (object); switch (prop_id) { case MYENCODER_PROP_SILENT: g_value_set_boolean (value, filter->silent); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static gboolean myencoder_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { MyEncoder *filter; gboolean ret; filter = GST_MYENCODER (parent); GST_LOG_OBJECT (filter, "Received %s event: %" GST_PTR_FORMAT, GST_EVENT_TYPE_NAME (event), event); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CAPS: /* we should handle the format here */ ret = gst_pad_event_default (pad, parent, event); break; default: ret = gst_pad_event_default (pad, parent, event); break; } return ret; } static gboolean myencoder_src_event (GstPad * pad, GstObject * parent, GstEvent * event) { MyEncoder *filter; gboolean ret; filter = GST_MYENCODER (parent); GST_LOG_OBJECT (filter, "Received %s event: %" GST_PTR_FORMAT, GST_EVENT_TYPE_NAME (event), event); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CAPS: /* we should fixate the caps here */ ret = gst_pad_event_default (pad, parent, event); break; default: ret = gst_pad_event_default (pad, parent, event); break; } return ret; } static GstFlowReturn myencoder_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { MyEncoder *filter; filter = GST_MYENCODER (parent); if (filter->silent == FALSE) g_print ("I'm plugged, therefore I'm in.\n"); /* just push out the incoming buffer without touching it */ return gst_pad_push (filter->srcpad, buf); } static void myencoder_finalize (GObject * object) { MyEncoder *filter = GST_MYENCODER (object); gst_object_unref (filter->sinkpad); gst_object_unref (filter->srcpad); G_OBJECT_CLASS (myencoder_parent_class)->finalize (object); } static GType myencoder_get_type (void) { static GType myencoder_type = 0; if (!myencoder_type) { static const GTypeInfo myencoder_info = { sizeof (MyEncoderClass), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) myencoder_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (MyEncoder), 0, /* n_preallocs */ (GInstanceInitFunc) myencoder_init, NULL /* value_table */ }; myencoder_type = g_type_register_static (GST_TYPE_ELEMENT, "MyEncoder", &myencoder_info, 0); } return myencoder_type; } ``` 在这个示例中,我们实现了一个简单的编码插件,其中包括一个sinkpad和一个srcpad,用于接收和传输数据。当数据到达sinkpad时,插件将其编码并通过srcpad发送出去。当编码器启动时,它会输出一条消息。 要使用这个插件,你需要将它编译成共享库文件(.so或.dll),并将其安装到gstreamer插件目录中。然后,你可以使用gst-launch或其他gstreamer工具来测试你的编码器插件

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值