I have created a 2-to-1 simple element called ntoone. My question now is how to run it (an example gst-launch using 2 videotestsrc and 1 autosink). It has two static "any" sink pads called video_sink and klv_sink and are added to a collection. Here is the code:
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <gst/gst.h>
#include "gstntoone.h"
#include <opencv/cv.h>
#include <opencv/highgui.h>
GST_DEBUG_CATEGORY_STATIC (gst_ntoone_debug);
#define GST_CAT_DEFAULT gst_ntoone_debug
enum
{
PROP_0,
PROP_SILENT,
LINE_COLOR
};
/* the capabilities of the inputs and outputs.
*
* describe the real formats here.
*/
//Creates a template for the pads. In the _init() function, you can create
//as many pads you want from these templates.
static GstStaticPadTemplate video_sink_factory = GST_STATIC_PAD_TEMPLATE ("video_sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("ANY")
);
static GstStaticPadTemplate klv_sink_factory = GST_STATIC_PAD_TEMPLATE ("klv_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")
);
GST_BOILERPLATE (GstNtoone, gst_ntoone, GstElement,
GST_TYPE_ELEMENT);
//function prototypes
static void gst_ntoone_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_ntoone_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean gst_ntoone_set_caps (GstPad * pad, GstCaps * caps);
static GstFlowReturn gst_ntoone_collected (GstCollectPads * pads, GstNtoone * filter);
/* GObject vmethod implementations */
static void
gst_ntoone_base_init (gpointer gclass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
//Describe the element's details
// Plugin name
// Plugin type
// A brief description
// Author and email (email is optional)
gst_element_class_set_details_simple(element_class,
"Plugin Template",
"Ntoone",
"Generic Chain Element",
"Jason Trinidad [email protected]");
//Register the tamplates. They can be used
//in the init() function to create pads
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 (&video_sink_factory));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&klv_sink_factory));
}
/* initialize the plugin's class */
static void
gst_ntoone_class_init (GstNtooneClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gobject_class->set_property = gst_ntoone_set_property;
gobject_class->get_property = gst_ntoone_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, LINE_COLOR,
g_param_spec_string ("line_color", "Line_color", "Chenge the color of the line", "red", G_PARAM_READWRITE));
}
/* initialize the new element
* instantiate pads and add them to element
*/
static void
gst_ntoone_init (GstNtoone * filter,
GstNtooneClass * gclass)
{
filter->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
gst_pad_set_getcaps_function (filter->srcpad,
GST_DEBUG_FUNCPTR(gst_pad_proxy_getcaps));
filter->sinkpad1 = gst_pad_new_from_static_template (&video_sink_factory, "video_sink");
gst_pad_set_setcaps_function (filter->sinkpad1,
GST_DEBUG_FUNCPTR(gst_ntoone_set_caps));
gst_pad_set_getcaps_function (filter->sinkpad1,
GST_DEBUG_FUNCPTR(gst_pad_proxy_getcaps));
filter->sinkpad2 = gst_pad_new_from_static_template (&klv_sink_factory, "klv_sink");
gst_pad_set_setcaps_function (filter->sinkpad2,
GST_DEBUG_FUNCPTR(gst_ntoone_set_caps));
gst_pad_set_getcaps_function (filter->sinkpad2,
GST_DEBUG_FUNCPTR(gst_pad_proxy_getcaps));
filter->collect = gst_collect_pads_new ();
gst_collect_pads_set_function (filter->collect,
(GstCollectPadsFunction) gst_ntoone_collected, filter);
gst_collect_pads_add_pad (filter->collect, filter->sinkpad1, sizeof (GstCollectData));
gst_collect_pads_add_pad (filter->collect, filter->sinkpad2, sizeof (GstCollectData));
gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad1);
gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad2);
gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
filter->silent = FALSE;
}
/*-------------------------------------------------------------------
* _set_property() is used to set arguments in the element.
* they can be used when running a pipelin by just typing the
* property name and the value right next to the plugin
* e.g. gst-launch -v -m videontoonesrc pattern=snow ! ntoone line_color=green ! autovideosink
* where pattern and line_color are properties
-------------------------------------------------------------------*/
static void
gst_ntoone_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstNtoone *filter = GST_NTOONE (object);
switch (prop_id) {
case PROP_SILENT:
filter->silent = g_value_get_boolean (value);
break;
case LINE_COLOR:
g_free (filter->line_color);
filter->line_color = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_ntoone_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstNtoone *filter = GST_NTOONE (object);
switch (prop_id) {
case PROP_SILENT:
g_value_set_boolean (value, filter->silent);
break;
case LINE_COLOR:
g_value_set_string (value, filter->line_color);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/* GstElement vmethod implementations */
/* this function handles the link with other elements */
static gboolean
gst_ntoone_set_caps (GstPad * pad, GstCaps * caps)
{
GstStructure *structure = gst_caps_get_structure(caps,0);
GstNtoone *filter;
GstPad *otherpad;
filter = GST_NTOONE (gst_pad_get_parent (pad));
gst_structure_get_int (structure, "rate", &filter->srcpad);
otherpad = (pad == filter->srcpad) ? filter->sinkpad1 : filter->srcpad;
gst_object_unref (filter);
return gst_pad_set_caps (otherpad, caps);
}
static GstFlowReturn
gst_ntoone_collected (GstCollectPads * pads, GstNtoone * filter)
{
guint size;
GstCollectData *cdata;
GstBuffer *outbuf, *sink1buf, *sink2buf;
GstFlowReturn ret = GST_FLOW_OK;
GSList *collected;
guint nsamples;
guint ncollected = 0;
gboolean empty = TRUE;
size = gst_collect_pads_available (pads); //Query how much bytes can be read from each queued buffer.
//This means that the result of this call is the maximum
//number of bytes that can be read from each of the pads.
GST_DEBUG_OBJECT (filter, "Starting to collect %u bytes", size);
collected = pads->data;
cdata = (GstCollectData *) collected->data;
sink1buf = gst_collect_pads_take_buffer (pads, cdata, size);
collected = collected->next;
cdata = (GstCollectData *) collected->data;
sink2buf = gst_collect_pads_take_buffer (pads, cdata, size);
gst_pad_push(filter->srcpad,sink1buf);
return ret;
goto eos;
eos:
{
GST_DEBUG_OBJECT (filter, "no data available, must be EOS");
gst_buffer_unref (outbuf);
gst_pad_push_event (filter->srcpad, gst_event_new_eos ());
return -3;
}
}
/* entry point to initialize the plug-in
* initialize the plug-in itself
* register the element factories and other features
*/
static gboolean
plugin_init (GstPlugin * plugin)
{
/* debug category for filtering log messages
*
* exchange the string 'Ntoone plugin' with your description
*/
GST_DEBUG_CATEGORY_INIT (gst_ntoone_debug, "ntoone",
0, "Template plugin");
return gst_element_register (plugin, "ntoone", GST_RANK_NONE,
GST_TYPE_NTOONE);
}
#ifndef PACKAGE
#define PACKAGE "pluginntoone"
#endif
GST_PLUGIN_DEFINE (
GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"ntoone",
"Template Example",
plugin_init,
"0.10.28",
"GPL",
"GStreamer",
"http://gstreamer.net/"
)
Thanks
First check that your element shows up in gst-inspect.
Then you can use it using gst-launch as below:
You can also specify the pads directly
When there is no '!' a new branch of the media graph is started.