参考资料:
Constructing the Boilerplate
gstreamer插件-CSDN博客
在Constructing the Boilerplate 里面有生成插件的例子,
shell $ git clone https://gitlab.freedesktop.org/gstreamer/gst-template.git
使用里面的工具自动生成一个插件程序,比如MyFilter
shell $ cd gst-template/gst-plugin/src
shell $ ../tools/make_element MyFilter
注意,这样生成的自定义的element的名字使用起来应该是my_filter,
画一下图,就比较容易理解生成的代码结构
class的定义,init
element的定义,init
pad(sink,src)的定义
属性的设置和获取处理
chain的处理
event事件的处理
代码参考
/*** SECTION:element-myfilter** FIXME:Describe myfilter here.** <refsect2>* <title>Example launch line</title>* |[* gst-launch -v -m fakesrc ! myfilter ! fakesink silent=TRUE* ]|* </refsect2>*/a#ifdef HAVE_CONFIG_H
# include <config.h>
#endif#ifndef __GST_MYFILTER_H__
#define __GST_MYFILTER_H__#include <gst/gst.h>
#include <stdio.h>G_BEGIN_DECLS#define GST_TYPE_MYFILTER (gst_my_filter_get_type())
G_DECLARE_FINAL_TYPE (GstMyFilter, gst_my_filter,GST, MYFILTER, GstElement)struct _GstMyFilter
{GstElement element;GstPad *sinkpad, *srcpad;gboolean width;gboolean height;gboolean silent;
};G_END_DECLS#endif /* __GST_MYFILTER_H__ */GST_DEBUG_CATEGORY_STATIC (gst_my_filter_debug);
#define GST_CAT_DEFAULT gst_my_filter_debug#define DEFAULT_PROP_WIDTH 0 /* Original */
#define DEFAULT_PROP_HEIGHT 0 /* Original *//* Filter signals and args */
enum
{/* FILL ME */LAST_SIGNAL
};enum
{PROP_0,PROP_SILENT,PROP_WIDTH,PROP_HEIGHT
};/* 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",GST_PAD_SRC,GST_PAD_ALWAYS,GST_STATIC_CAPS ("video/x-raw, ""width = (int) [96, 1920], height = (int) [96, 1080]"));#define gst_my_filter_parent_class parent_class
G_DEFINE_TYPE (GstMyFilter, gst_my_filter, GST_TYPE_ELEMENT);GST_ELEMENT_REGISTER_DEFINE (my_filter, "my_filter", GST_RANK_NONE,GST_TYPE_MYFILTER);static void gst_my_filter_set_property (GObject * object,guint prop_id, const GValue * value, GParamSpec * pspec);
static void gst_my_filter_get_property (GObject * object,guint prop_id, GValue * value, GParamSpec * pspec);static gboolean gst_my_filter_sink_event (GstPad * pad,GstObject * parent, GstEvent * event);
static GstFlowReturn gst_my_filter_chain (GstPad * pad,GstObject * parent, GstBuffer * buf);
/* GObject vmethod implementations *//* initialize the myfilter's class */
static void
gst_my_filter_class_init (GstMyFilterClass * klass)
{GObjectClass *gobject_class;GstElementClass *gstelement_class;gobject_class = (GObjectClass *) klass;gstelement_class = (GstElementClass *) klass;gobject_class->set_property = gst_my_filter_set_property;gobject_class->get_property = gst_my_filter_get_property;g_object_class_install_property (gobject_class, PROP_SILENT,g_param_spec_boolean ("silent", "Silent", "Produce verbose output ?",FALSE, G_PARAM_READWRITE));g_object_class_install_property (gobject_class, PROP_WIDTH,g_param_spec_uint ("width", "Width","Width (0 = original)",0, G_MAXINT, DEFAULT_PROP_WIDTH,G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));g_object_class_install_property (gobject_class, PROP_HEIGHT,g_param_spec_uint ("height", "Height","Height (0 = original)",0, G_MAXINT, DEFAULT_PROP_HEIGHT,G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));gst_element_class_set_details_simple (gstelement_class,"MyFilter","FIXME:Generic","FIXME:Generic Template Element", " <<user@hostname.org>>");gst_element_class_add_pad_template (gstelement_class,gst_static_pad_template_get (&src_factory));gst_element_class_add_pad_template (gstelement_class,gst_static_pad_template_get (&sink_factory));
}/* initialize the new element* instantiate pads and add them to element* set pad callback functions* initialize instance structure*/
static void
gst_my_filter_init (GstMyFilter * filter)
{filter->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");gst_pad_set_event_function (filter->sinkpad,GST_DEBUG_FUNCPTR (gst_my_filter_sink_event));gst_pad_set_chain_function (filter->sinkpad,GST_DEBUG_FUNCPTR (gst_my_filter_chain));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_factory, "src");GST_PAD_SET_PROXY_CAPS (filter->srcpad);gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);filter->silent = TRUE;
}static void
gst_my_filter_set_property (GObject * object, guint prop_id,const GValue * value, GParamSpec * pspec)
{GstMyFilter *filter = GST_MYFILTER (object);switch (prop_id) {case PROP_SILENT:filter->silent = g_value_get_boolean (value);break;case PROP_WIDTH:filter->width = g_value_get_boolean (value);break;case PROP_HEIGHT:filter->height = g_value_get_boolean (value);break;default:G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);break;}
}static void
gst_my_filter_get_property (GObject * object, guint prop_id,GValue * value, GParamSpec * pspec)
{GstMyFilter *filter = GST_MYFILTER (object);switch (prop_id) {case PROP_SILENT:g_value_set_boolean (value, filter->silent);break;case PROP_WIDTH:g_value_set_boolean (value, filter->width);break;case PROP_HEIGHT:g_value_set_boolean (value, filter->height);break;default:G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);break;}
}/* GstElement vmethod implementations *//* this function handles sink events */
static gboolean
gst_my_filter_sink_event (GstPad * pad, GstObject * parent,GstEvent * event)
{GstMyFilter *filter;gboolean ret;filter = GST_MYFILTER (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:{GstCaps *caps;GstStructure *structure;gst_event_parse_caps (event, &caps);structure = gst_caps_get_structure(caps, 0);gint width, height;gst_structure_get_int(structure, "width", &width);gst_structure_get_int(structure, "height", &height);filter->width = width;filter->height = height;/* and forward */ret = gst_pad_event_default (pad, parent, event);break;}default:ret = gst_pad_event_default (pad, parent, event);break;}return ret;
}/* chain function* this function does the actual processing*/
static GstFlowReturn
gst_my_filter_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
{GstMyFilter *filter;filter = GST_MYFILTER (parent);if (filter->silent == FALSE){g_print ("I'm plugged, therefore I'm in.\n");}GstFlowReturn ret = gst_pad_push (filter->srcpad, buf);/* just push out the incoming buffer without touching it */return ret;
}/* entry point to initialize the plug-in* initialize the plug-in itself* register the element factories and other features*/
static gboolean
myfilter_init (GstPlugin * myfilter)
{/* debug category for filtering log messages** exchange the string 'Template myfilter' with your description*/GST_DEBUG_CATEGORY_INIT (gst_my_filter_debug, "myfilter",0, "Template myfilter");return GST_ELEMENT_REGISTER (my_filter, myfilter);
}/* PACKAGE: this is usually set by meson depending on some _INIT macro* in meson.build and then written into and defined in config.h, but we can* just set it ourselves here in case someone doesn't use meson to* compile this code. GST_PLUGIN_DEFINE needs PACKAGE to be defined.*/
#ifndef PACKAGE
#define PACKAGE "myfirstmyfilter"
#endif/* gstreamer looks for this structure to register myfilters** exchange the string 'Template myfilter' with your myfilter description*/
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,GST_VERSION_MINOR,myfilter,"my_filter",myfilter_init,PACKAGE_VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
在gst_my_filter_chain方法中,
static GstFlowReturn
gst_my_filter_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
{
GstMyFilter *filter;
filter = GST_MYFILTER (parent);
if (filter->silent == FALSE){
g_print ("I'm plugged, therefore I'm in.\n");
}
GstFlowReturn ret = gst_pad_push (filter->srcpad, buf);
/* just push out the incoming buffer without touching it */
return ret;
}
可以使用Basic tutorial 8: Short-cutting the pipeline 例子的的方法来获取buffer中的内存数据,来进行操作,
gst_buffer_map (buffer, &map, GST_MAP_WRITE);raw = (gint16 *)map.data;
比如数据格式是RGB,获取到长宽后,可以进行颜色转换,画面镜像处理等等,
就比如最近欧洲杯里讨论的比较火的广告内容区域化转换处理,就可以在gst_my_filter_chain里进行