gstreamer插件开发 - sink插件开发
gstreamer的SINK插件,只有sink pad 没有srcpad,gstreamer中有一个基类GstBaseSink,要想要实现最长用的sink插件功能,只要继承这个基类,就可以实现sink插件最基本的功能,然后剩下的就是你自己往上面添砖加瓦了。
废话不多说,下面开始介绍创建sink插件的过程,这里我以项目中的例子来说来,该例子是创建了一个类似于filesink的插件,但是为了满足项目灵活的需求,所以需要自行设计一个保存本地文件的插件!
refer: http://blog.chinaunix.net/uid-24922718-id-3770053.html
废话不多说,下面开始介绍创建sink插件的过程,这里我以项目中的例子来说来,该例子是创建了一个类似于filesink的插件,但是为了满足项目灵活的需求,所以需要自行设计一个保存本地文件的插件!
创建插件的方法可以参考插件手册,下面来说说如何修改这个模板创建的插件使其成为sink插件!
struct _Gstaudiofilter { GstBaseSink element; //GstPad *sinkpad; gboolean silent; gchar* filename; gboolean kaiguan; }; struct _GstaudiofilterClass { GstBaseSinkClass parent_class; gint (*eos)(Gstaudiofilter *sink); gint (*fuck)(Gstaudiofilter *sink); };这段代码是插件头文件中的插件类的申明,刚接触gstreamer的同鞋可能会看不明白为什么会有两个插件的结构体,这其实是gobject的特有属性,因为glib这套是模仿面向对象的,所以再设计上就做了这样的,在这可以简单的理解为, _Gstaudiofilter就是类对象,再实际应用中用的,里面存放的一般都是类的属性,_GstaudiofilterClass就是类的结构,里面一般存放的是这个类的继承关系以及这个类的方法。 可以看到GstBaseSink element 和 GstBaseSinkClass parent_class,这两个定义了这个类是gstbasesink,gint (*eos)(Gstaudiofilter *sink);和 gint (*fuck)(Gstaudiofilter *sink);表示的是该类的方法,可以注意到这里用的是函数指针,这就是glib的设计方法,这样就能把这个类对象当面向对象中的使用方法一样来调用该类的方法了。这两个方法我们稍后再看,这其实就是为该类的信号进行定义的。
enum { /* FILL ME */ LAST_SIGNAL }; enum { PROP_0, //定义详细的插件属性 PROP_Location, PROP_Switch, PROP_SILENT }; /* the capabilities of the inputs and outputs. * * describe the real formats here. */ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ("ANY") ); //static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", //因为是sink插件,所以不应该有srcpad 所以将srcpad模板注释掉 // GST_PAD_SRC, // GST_PAD_ALWAYS, // GST_STATIC_CAPS ("ANY") // ); //GST_BOILERPLATE (Gstaudiofilter, gst_audiofilter, GstElement, // GST_TYPE_ELEMENT); GST_BOILERPLATE (Gstaudiofilter, gst_audiofilter, GstBaseSink ,GST_TYPE_BASE_SINK); //这个宏是关键,主要用来注册这个插件类,使这个插件继承自GstBaseSink static void gst_audiofilter_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_audiofilter_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static gboolean gst_audiofilter_set_caps (GstPad * pad, GstCaps * caps); //static GstFlowReturn gst_audiofilter_chain (GstPad * pad, GstBuffer * buf); static GstFlowReturn gst_audiofilter_render(GstBaseSink *sink, GstBuffer *buffer); static gboolean gst_audiofilter_start(GstBaseSink *sink); static gboolean gst_audiofilter_stop(GstBaseSink *sink); static gboolean gst_audiofilter_event(GstBaseSink *sink, GstEvent *event); static gint gst_audiofilter_eos_cb(Gstaudiofilter *sink); /* GObject vmethod implementations */ static void gst_audiofilter_base_init (gpointer gclass) { GstElementClass *element_class = GST_ELEMENT_CLASS (gclass); gst_element_class_set_details_simple(element_class, "audiofilter", "FIXME:Generic", "FIXME:Generic Template Element", "maoyikai <<user@hostname.org>>"); // gst_element_class_add_pad_template (element_class, // gst_static_pad_template_get (&src_factory)); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&sink_factory)); } static gint gst_audiofilter_fuck_cb(Gstaudiofilter *filter); /* initialize the audiofilter's class */ static void gst_audiofilter_class_init (GstaudiofilterClass * klass) //该函数是该插件类的结构初始化函数,在之前的头文件中的类结构中定义的方法什么都在这里初始化,赋值 { GObjectClass *gobject_class; GstBaseSinkClass *gstbasesink_class = GST_BASE_SINK_CLASS (klass); GstElementClass *gstelement_class; gobject_class = (GObjectClass *) klass; gstelement_class = (GstElementClass *) klass; gobject_class->set_property = gst_audiofilter_set_property; gobject_class->get_property = gst_audiofilter_get_property; g_object_class_install_property (gobject_class, PROP_Switch, g_param_spec_boolean ("swicth", "Socation", "switch off clip picture",FALSE , G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING)); //注册类属性的代码,可以发现参数定义了GST_PARAM_MUTABLE_PLAYING该属性可以在playing的过程中进行修改,g_param_spec_boolean这个宏定义了这个属性的值是什么类型的 g_object_class_install_property (gobject_class, PROP_Location, g_param_spec_string ("location", "File Location", "Location of the file to read", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_MUTABLE_PLAYING)); g_object_class_install_property (gobject_class, PROP_SILENT, g_param_spec_boolean ("silent", "Silent", "Produce verbose output ?", FALSE, G_PARAM_READWRITE)); //以下是继承子basesink的方法,对这些方法进行了重新的赋值,进行重载 gstbasesink_class->render = gst_audiofilter_render; //render方法是当数据流开始传送的时候会不停的调用这个函数 gstbasesink_class->stop = gst_audiofilter_stop; //stop方法当数据流停止的时候就会调用 gstbasesink_class->start = gst_audiofilter_start; //start方法当数据流开始的时候就会调用 gstbasesink_class->event = gst_audiofilter_event; //定义的是该插件接受到event事件时的处理函数 //为该插件定义信号参数,这个比较复杂,不过通常的使用还是很容易的,大家可以参考api手册, guint eossignal_id = g_signal_new("eos",G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,G_STRUCT_OFFSET (GstaudiofilterClass, eos),NULL,NULL, NULL, G_TYPE_INT,0,G_TYPE_NONE); g_signal_new ("fuck", G_TYPE_FROM_CLASS (klass),G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstaudiofilterClass,fuck), NULL, NULL, NULL, G_TYPE_INT, 0, G_TYPE_NONE); //为注册的信号处理函数赋值,可以看出glib的面向对象设计方法的设计其实就是函数指针 klass->fuck = gst_audiofilter_fuck_cb; klass->eos =gst_audiofilter_eos_cb; } static gint gst_audiofilter_eos_cb(Gstaudiofilter *sink) { printf("get eos signal\n"); return 1000; } static gint gst_audiofilter_fuck_cb(Gstaudiofilter *filter) { return 100; } static gboolean gst_audiofilter_event(GstBaseSink *sink, GstEvent *event) { switch(event-> type) { case GST_EVENT_FLUSH_START: { printf("event flush start..........\n"); }break; case GST_EVENT_FLUSH_STOP: { printf("event flush stop..........\n"); }break; case GST_EVENT_EOS: { printf("event flush EOS..........\n"); }break; default:break; } } static GstFlowReturn gst_audiofilter_render(GstBaseSink *sink, GstBuffer *buffer) { Gstaudiofilter *audiofiltersink; audiofiltersink = GST_AUDIOFILTER(sink); if(swicthoff) { FILE* f = fopen(audiofiltersink->filename,"wb"); if(!f) { printf("can't open file to write\n"); return GST_FLOW_ERROR; } fwrite(buffer->data,1,buffer->size,f); fclose(f); swicthoff = FALSE; g_free(audiofiltersink->filename);
refer: http://blog.chinaunix.net/uid-24922718-id-3770053.html