Last active
August 12, 2019 11:47
-
-
Save szihs/6d74e0076ff016f2c5f443c3daffe496 to your computer and use it in GitHub Desktop.
GST Sample Filter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* SECTION:element-myfilter | |
* | |
* FIXME:Describe myfilter here. | |
* | |
* <refsect2> | |
* <title>Example launch line</title> | |
* |[ | |
* gst-launch -v -m fakesrc ! myfilter ! fakesink silent=TRUE | |
* ]| | |
* </refsect2> | |
*/ | |
#ifdef HAVE_CONFIG_H | |
# include <config.h> | |
#endif | |
#include <gst/gst.h> | |
#include "gstmyfilter.h" | |
GST_DEBUG_CATEGORY_STATIC (gst_my_filter_debug); | |
#define GST_CAT_DEFAULT gst_my_filter_debug | |
/* Filter signals and args */ | |
enum | |
{ | |
/* FILL ME */ | |
LAST_SIGNAL | |
}; | |
enum | |
{ | |
PROP_0, | |
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", | |
GST_PAD_SRC, | |
GST_PAD_ALWAYS, | |
GST_STATIC_CAPS ("ANY") | |
); | |
static GstStaticPadTemplate src2_factory = | |
GST_STATIC_PAD_TEMPLATE ( | |
"src2", | |
GST_PAD_SRC, | |
GST_PAD_REQUEST, | |
GST_STATIC_CAPS ( | |
"video/x-raw, " | |
"format=(string)RGB, " | |
"width = (int) [1, 2147483647], " | |
"height = (int)[1, 2147483647], " | |
"framerate = (fraction) [0/1, 2147483647/1]" | |
) | |
); | |
#define gst_my_filter_parent_class parent_class | |
G_DEFINE_TYPE (GstMyFilter, gst_my_filter, GST_TYPE_ELEMENT); | |
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); | |
static gboolean gst_my_filter_src_event (GstPad * pad, GstObject * parent, GstEvent * event); | |
static gboolean gst_my_filter_query (GstPad *pad, GstObject * parent, GstQuery * query); | |
static GstPad * gst_my_filter_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *name, const GstCaps *caps); | |
static void gst_my_filter_release_pad (GstElement *element, GstPad *pad); | |
/* 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)); | |
gst_element_class_set_details_simple(gstelement_class, | |
"MyFilter", | |
"FIXME:Generic", | |
"FIXME:Generic Template Element", | |
"HarshAggarwal <<[email protected]>>"); | |
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)); | |
gst_element_class_add_pad_template (gstelement_class, | |
gst_static_pad_template_get (&src2_factory)); | |
gstelement_class->request_new_pad = gst_my_filter_request_new_pad; | |
gstelement_class->release_pad = gst_my_filter_release_pad; | |
} | |
/* initialize the new element | |
* instantiate pads and add them to element | |
* set pad calback 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 = FALSE; | |
} | |
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; | |
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; | |
default: | |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); | |
break; | |
} | |
} | |
static GstPad * | |
gst_my_filter_request_new_pad (GstElement *element, | |
GstPadTemplate *templ, | |
const gchar *name, | |
const GstCaps *caps) | |
{ | |
GstMyFilter *filter = GST_MYFILTER (element); | |
GstMyFilterInputContext *context; | |
context = g_new0 (GstMyFilterInputContext, 1); | |
context->width = 100; | |
context->height = 100; | |
context->bpp = 4; | |
filter->src2pad = gst_pad_new_from_static_template (&src2_factory, "src2"); | |
// GST_PAD_SET_PROXY_CAPS (filter->src2pad); | |
// gst_pad_use_fixed_caps(filter->src2pad);//use_fixed_caps | |
gst_pad_set_element_private (filter->src2pad, context); | |
gst_pad_set_event_function (filter->src2pad, | |
GST_DEBUG_FUNCPTR(gst_my_filter_src_event)); | |
gst_pad_set_query_function (filter->src2pad, | |
GST_DEBUG_FUNCPTR(gst_my_filter_query)); | |
gst_element_add_pad (element, filter->src2pad); | |
return filter->src2pad; | |
} | |
static void | |
gst_my_filter_release_pad (GstElement *element, | |
GstPad *pad) | |
{ | |
GstMyFilterInputContext *context; | |
g_print("%s:%d --------------- \n", __func__, __LINE__); | |
context = gst_pad_get_element_private (pad); | |
g_free (context); | |
gst_element_remove_pad (element, pad); | |
} | |
/* 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; | |
gst_event_parse_caps (event, &caps); | |
/* do something with the caps */ | |
/* 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; | |
GstFlowReturn ret; | |
GstBuffer *buffer; | |
guint size; | |
filter = GST_MYFILTER (parent); | |
if (filter->silent == FALSE) | |
g_print ("I'm plugged, therefore I'm in.\n"); | |
ret = gst_pad_push (filter->srcpad, buf); | |
if (filter->src2pad) { | |
#if 1 | |
GstMyFilterInputContext *context; | |
context = gst_pad_get_element_private (filter->src2pad); | |
GST_DEBUG_OBJECT (filter->src2pad, "push hello"); | |
GstCaps *outcaps; | |
outcaps = gst_caps_new_simple ("video/x-raw", | |
"format", G_TYPE_STRING, "RGB", | |
"width", G_TYPE_INT, 300, | |
"height", G_TYPE_INT, 300, | |
"framerate", GST_TYPE_FRACTION, 24, 1, NULL); | |
ret = gst_pad_set_caps (filter->src2pad, outcaps); | |
ret = gst_pad_push (filter->src2pad, gst_buffer_ref(buf)); | |
size = context->width * context->height * context->bpp; | |
buffer = gst_buffer_new_and_alloc (size); | |
ret = gst_pad_push (filter->src2pad, buffer); | |
#else | |
ret = gst_pad_push (filter->src2pad, gst_buffer_ref(buf)); | |
#endif | |
} | |
/* just push out the incoming buffer without touching it */ | |
return ret; | |
} | |
/* Functions below print the Capabilities in a human-friendly format */ | |
static gboolean | |
print_field (GQuark field, const GValue * value, gpointer pfx) | |
{ | |
gchar *str = gst_value_serialize (value); | |
g_print (" %15s: %s\n", g_quark_to_string (field), str); | |
g_free (str); | |
return TRUE; | |
} | |
static gboolean | |
gst_my_filter_setcaps (GstMyFilter *filter, | |
GstCaps *caps) | |
{ | |
GstStructure *structure; | |
int width, height; | |
gboolean ret; | |
GstCaps *outcaps; | |
#if 0 | |
g_print("%s:%d --SET CAPS------------- \n", __func__, __LINE__); | |
structure = gst_caps_get_structure (caps, 0); | |
ret = gst_structure_get_int (structure, "width", &width); | |
ret = ret && gst_structure_get_int (structure, "height", &height); | |
if (!ret) { | |
GST_LOG_OBJECT (filter, "Hello error ----------<<<<< \n"); | |
return FALSE; | |
} | |
#endif | |
outcaps = gst_caps_new_simple ("video/x-raw", | |
"format", G_TYPE_STRING, "RGB", | |
"width", G_TYPE_INT, 300, | |
"height", G_TYPE_INT, 300, | |
"framerate", GST_TYPE_FRACTION, 24, 1, NULL); | |
ret = gst_pad_set_caps (filter->src2pad, outcaps); | |
gst_caps_unref (outcaps); | |
return ret; | |
} | |
static gboolean | |
gst_my_filter_query (GstPad *pad, GstObject * parent, GstQuery * query) | |
{ | |
gboolean ret; | |
GstMyFilter *filter = GST_MYFILTER (parent); | |
switch (GST_QUERY_TYPE (query)) { | |
case GST_QUERY_CAPS: | |
{ | |
g_print("%s:%d --------------- \n", __func__, __LINE__); | |
#if 0 | |
GstPad *otherpad; | |
GstCaps *temp, *caps, *filt, *tcaps; | |
gint i; | |
otherpad = (pad == filter->srcpad) ? filter->sinkpad : | |
filter->srcpad; | |
caps = gst_pad_get_allowed_caps (otherpad); | |
gst_query_parse_caps (query, &filt); | |
/* We support *any* samplerate, indifferent from the samplerate | |
* supported by the linked elements on both sides. */ | |
for (i = 0; i < gst_caps_get_size (caps); i++) { | |
GstStructure *structure = gst_caps_get_structure (caps, i); | |
gst_structure_remove_field (structure, "rate"); | |
} | |
/* make sure we only return results that intersect our | |
* padtemplate */ | |
tcaps = gst_pad_get_pad_template_caps (pad); | |
if (tcaps) { | |
temp = gst_caps_intersect (caps, tcaps); | |
gst_caps_unref (caps); | |
gst_caps_unref (tcaps); | |
caps = temp; | |
} | |
/* filter against the query filter when needed */ | |
if (filt) { | |
temp = gst_caps_intersect (caps, filt); | |
gst_caps_unref (caps); | |
caps = temp; | |
} | |
gst_query_set_caps_result (query, caps); | |
gst_caps_unref (caps); | |
#else | |
GstCaps *outcaps; | |
outcaps = gst_caps_new_simple ("video/x-raw", | |
"width", G_TYPE_INT, 300, | |
"height", G_TYPE_INT, 300, | |
"format", G_TYPE_STRING, "RGB", | |
"framerate", GST_TYPE_FRACTION, 24, 1, NULL); | |
if (!gst_pad_set_caps (filter->src2pad, outcaps)) { | |
GST_ELEMENT_ERROR (filter, CORE, NEGOTIATION, (NULL), | |
("Some debug information here")); | |
} | |
gst_caps_unref(outcaps); | |
#endif | |
ret = TRUE; | |
break; | |
} | |
default: | |
ret = gst_pad_query_default (pad, parent, query); | |
break; | |
} | |
return ret; | |
} | |
/* this function handles sink events */ | |
static gboolean | |
gst_my_filter_src_event (GstPad * pad, GstObject * parent, GstEvent * event) | |
{ | |
GstMyFilter *filter; | |
gboolean ret; | |
filter = GST_MYFILTER (parent); | |
g_print("==EVENT===============>>> %s:%d --------------- \n", __func__, __LINE__); | |
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; | |
gst_event_parse_caps (event, &caps); | |
/* do something with the caps */ | |
#if 0 | |
GstStructure *structure = gst_caps_get_structure(caps, 0); | |
g_assert(structure); | |
g_print ("%s\n", gst_structure_get_name (structure)); | |
gst_structure_foreach (structure, print_field, (gpointer) NULL); | |
// const gchar *format = gst_structure_get_string(structure, "format"); | |
//#else | |
ret = gst_my_filter_setcaps (filter, caps); | |
#endif | |
/* and forward */ | |
ret = gst_pad_event_default (pad, parent, event); | |
break; | |
} | |
default: | |
ret = gst_pad_event_default (pad, parent, event); | |
break; | |
} | |
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 fltering 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 (myfilter, "myfilter", GST_RANK_NONE, | |
GST_TYPE_MYFILTER); | |
} | |
/* PACKAGE: this is usually set by autotools depending on some _INIT macro | |
* in configure.ac and then written into and defined in config.h, but we can | |
* just set it ourselves here in case someone doesn't use autotools 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, | |
"Template myfilter", | |
myfilter_init, | |
PACKAGE_VERSION, | |
GST_LICENSE, | |
GST_PACKAGE_NAME, | |
GST_PACKAGE_ORIGIN | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment