GStreamer Bus的一个细节

GStreamer的Bus系统主要用于向用户提供内部Elements的事件信息。使用GStreamer的Bus系统,只要调用gst_bus_add_watch,并且注册一个Callback即可。但问题在于调用这个接口的时机,及用于处理Bus事件的线程。Callback内部以glib的Source机制实现,Source要attach到一个GMainContext上,且需要有一个GMainloop来侦听这个Context。通常,调用gst_bus_add_watch的线程,在未做过任何处理的情况下,这个Source attach的GMainContext是NULL,也就是Default Main Context。而侦听Default Main Context的线程未必就是调用者线程,这样在做资源回收时,会出现多线程互斥问题。

需要回调函数在调用者线程中执行的方法如下:

1. 在创建调用者线程之后,创建该线程自己的GMainContext与GMainloop,然后调用g_main_context_push_thread_default,将该Context作为线程自己的默认Context,并使用GMainloop侦听;

2. 之后再在该线程中调用gst_bus_add_watch,则Callback会在调用者线程中执行,避免了多线程互斥的问题。

此方法同时避免了应用的主线程负担过重的问题。另外,所有基于gio的应用,也会由于使用了g_main_context_push_thread_default,使得各线程的负载分散化。

 

要实现一个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@example.com>"); } 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、付费专栏及课程。

余额充值