当前位置 : 主页 > 编程语言 > java >

[GStreamer] 插件编写 —— filter element

来源:互联网 收集:自由互联 发布时间:2022-09-29
源码: ObtFilter.h #pragma once #include gst/gst.h #define VERSION "1.0" #define PACKAGE "obtplugin" //mandatary for gst_plugin_desc G_BEGIN_DECLS /* property id list */ enum { PROP_0 , PROP_SILENT , PROP_CNT }; /* instance struct */ typ


源码:

ObtFilter.h

#pragma once

#include <gst/gst.h>

#define VERSION "1.0"
#define PACKAGE "obtplugin" //mandatary for gst_plugin_desc


G_BEGIN_DECLS

/*
property id list
*/
enum{
PROP_0,
PROP_SILENT,
PROP_CNT
};

/*
instance struct
*/
typedef struct _GstObtFilter
{
GstElement element;

//pads
GstPad* srcpad; //src pad
GstPad* sinkpad; //sink pad

gboolean silent;

}GstObtFilter;


/*
class struct
*/
typedef struct _GstObtFilterClass
{
GstElementClass parent_class;
}GstObtFilterClass;


/*
declare get_type Func, defined in G_DEFINE_TYPE
*/
GType gst_obt_filter_get_type(void);

/*
Standard macros for defining types for this element.
*/
#define GST_TYPE_OBT_FILTER (gst_obt_filter_get_type()) //return GType
//get a GstObtFilter ptr from any ptr #obj ,if obj is GST_TYPE_OBT_FILTER GType , return result , otherwise return null
#define GST_OBT_FILTER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OBT_FILTER,GstObtFilter))
//get a GstObtFilterClass ptr from any ptr #obj ,if obj is GST_TYPE_OBT_FILTER GType , return result , otherwise return null
#define GST_OBT_FILTER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OBT_FILTER,GstObtFilterClass))
#define GST_IS_OBT_FILTER(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OBT_FILTER))
#define GST_IS_OBT_FILTER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OBT_FILTER))

G_END_DECLS

//GST_ELEMENT_REGISTER_DECLARE(obt_filter)

ObtFilter.c

#include "ObtFilter.h"
#include <gst/gstelement.h>
#include <gst/audio/audio-format.h>
#include <gst/gstpad.h>
#include <gst/gstplugin.h>
#include <gst/gstconfig.h>
#include <gobject/gparam.h>

static GstBuffer *gst_obt_filter_process_data(GstObtFilter* filter,GstBuffer* buf);
static gboolean gst_obt_filter_stop_processing(GstObtFilter* filter);
static gboolean gst_obt_filter_allocate_memory(GstObtFilter* filter);
static gboolean gst_obt_filter_free_memory(GstObtFilter* filter);


/***************************************** boilerplate Funcs [START] *****************************************/

/*
define a GType named GstObtFilter.
biolerplate Func's prefix is "gst_obt_filter".
current GType is a GST_TYPE_ELEMENT, every new GType should be a already defined GType
*/
G_DEFINE_TYPE(GstObtFilter, gst_obt_filter, GST_TYPE_ELEMENT);
//GST_ELEMENT_REGISTER_DEFINE(obt_filter, "obt-filter", GST_RANK_NONE, GST_TYPE_OBT_FILTER);

//#define gst_obt_filter_parent_class parent_class

/*
create sink template for instantiating in xxx_init
*/
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE(
"sink", //short name of pad
GST_PAD_SINK, //pad direction - sink - input
GST_PAD_ALWAYS, //existence - always
GST_STATIC_CAPS("ANY") //support data type - any
);
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE(
"src", //short name of pad
GST_PAD_SRC, //pad direction - src - output
GST_PAD_ALWAYS, //existence - always
GST_STATIC_CAPS("ANY") //support data type - any
);
static GstStaticPadTemplate sink_factory_1 = GST_STATIC_PAD_TEMPLATE(
"sink_%u",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS(
"audio/x-raw, "
"format = (string) " GST_AUDIO_NE(S16) ", "
"channels = (int) { 1, 2 }, "
"rate = (int) [ 8000, 96000 ]"
)
);


/*
[sink pad] GstBuffer Object deal Func
gst_app_src_push_buffer is used to push a GstBuffer into queue of src-element.
sink pad of src-element will consume item of the queue.
*/
static GstFlowReturn gst_obt_filter_chain(GstPad* pad/*pad reveive buffer*/ , GstObject *parent, GstBuffer *buf/*to be precessed*/)
{
//g_print("gst_obt_filter_chain\n");
GstObtFilter *filter = GST_OBT_FILTER(parent);

/*
GstBuffer *outbuf;

outbuf = gst_obt_filter_process_data(filter, buf);
//gst_buffer_unref(buf);
if (!outbuf) {
// something went wrong - signal an error
GST_ELEMENT_ERROR(GST_ELEMENT(filter), STREAM, FAILED, (NULL), (NULL));
return GST_FLOW_ERROR;
}
*/

return gst_pad_push(filter->srcpad, buf);
}

/*
[sink pad] GstEvent Object deal Func
gst_element_send_event is used to send event to target element
*/
static gboolean gst_obt_filter_event(GstPad* pad/*pad reveive event*/, GstObject *parent, GstEvent *event/*to be preocessed*/)
{
gboolean ret;
GstObtFilter *filter = GST_OBT_FILTER(parent);

g_print("event : %s \n",GST_EVENT_TYPE_NAME(event));

switch (GST_EVENT_TYPE(event)) {
case GST_EVENT_CAPS:
ret = gst_pad_push_event(filter->srcpad, event); /* push the event downstream */
break;
case GST_EVENT_EOS:
gst_obt_filter_stop_processing(filter);
ret = gst_pad_event_default(pad, parent, event); //default deal transaction
break;
default:
ret = gst_pad_event_default(pad, parent, event);
break;
}

return ret;
}

/*
[sink pad] GstQuery Object deal Func
gst_pad_query is used to send a GstQuery to target pad.
gst_element_query is used to send a GstQuery to target element, pipeline is also a element.
*/
static gboolean gst_obt_filter_src_query(GstPad* pad, GstObject* parent, GstQuery* query)
{
gboolean ret;
GstObtFilter *filter = GST_OBT_FILTER(parent);

switch (GST_QUERY_TYPE(query)) {
case GST_QUERY_POSITION:
/* we should report the current position */
break;
case GST_QUERY_DURATION:
/* we should report the duration here */
break;
case GST_QUERY_CAPS:
/* we should report the supported caps here */
break;
default:
/* just call the default handler */
ret = gst_pad_query_default(pad, parent, query); //榛樿handler
break;
}
return ret;
}

/*
[element] everytime element state changed , this Func is called
*/
static GstStateChangeReturn gst_obt_filter_change_state(GstElement *element, GstStateChange transition)
{
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
GstObtFilter *filter = GST_OBT_FILTER(element);

/*
Note that upwards (NULL=>READY, READY=>PAUSED, PAUSED=>PLAYING) and downwards (PLAYING=>PAUSED, PAUSED=>READY, READY=>NULL) state changes
are handled in two separate blocks with the downwards state change handled only after we have chained up to the parent class's state change function.
This is necessary in order to safely handle concurrent access by multiple threads.
*/

//process upwards state change
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
if (!gst_obt_filter_allocate_memory(filter)) //require for resource, memory / libs / ... are included
return GST_STATE_CHANGE_FAILURE;
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
//dosomething
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
//dosomething
break;
default:
break;
}



//call state changed Func of parent class.
ret = GST_ELEMENT_CLASS (gst_obt_filter_parent_class)->change_state (element, transition);
if (ret == GST_STATE_CHANGE_FAILURE)
return ret;

/*
GstElementClass* class = GST_ELEMENT_GET_CLASS(element);
ret = class->change_state(element, transition);
if (ret == GST_STATE_CHANGE_FAILURE)
return ret;
*/

//process downwards state change
switch (transition) {
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
//dosomething
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
//dosomething
break;
case GST_STATE_CHANGE_READY_TO_NULL:
gst_obt_filter_free_memory(filter);
break;
default:
break;
}


return ret;
}

/*
[element] property setting deal Func
g_object_set is used to set property of GObject, every Gst Object is a GObject
*/
static void gst_obt_filter_set_property(GObject* object, guint prop_id, const GValue * value, GParamSpec *pspec)
{
GstObtFilter* filter = GST_OBT_FILTER(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;
}
}

/*
[element] property getting deal Func
g_object_get is used to get property of GObject, every Gst Object is a GObject
*/
static void gst_obt_filter_get_property(GObject* object, guint prop_id, GValue * value, GParamSpec *pspec)
{
GstObtFilter *filter = GST_OBT_FILTER(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;
}
}


/*
[element] class init Func
*/
static void gst_obt_filter_class_init(GstObtFilterClass *klass)
{
g_print("gst_obt_filter_class_init\n");
GstElementClass *element_class = GST_ELEMENT_CLASS(klass); //for others
GObjectClass *object_class = G_OBJECT_CLASS(klass); //for property setter and getter

//meta data
gst_element_class_set_static_metadata(element_class,
"[meta data]Filter Demo of Obt Plugin",
"[meta data]ObtPlugin/Filter Demo",
"[meta data]Shows the basic structure of a plugin",
"[meta data]obentul <ykun089@163.com>");

//register state change funcution
element_class->change_state = gst_obt_filter_change_state;

//register property setter and getter
object_class->set_property = gst_obt_filter_set_property;
object_class->get_property = gst_obt_filter_get_property;

//reigster properties
//silent
//g_object_class_install_property(
// object_class,
// PROP_SILENT,
// g_param_spec_boolean("property-name: silent", "property-type: boolean", "test propery,no specific function", FALSE, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))
//);

//register 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(&sink_factory));
}


/*
[element] instance init Func
*/
static void gst_obt_filter_init(GstObtFilter *filter)
{
g_print("gst_obt_filter_init\n");
//instantiates and assigns pads
filter->srcpad = gst_pad_new_from_static_template(&src_factory,"src_%u");
filter->sinkpad = gst_pad_new_from_static_template(&sink_factory, "sink_%u");

//add pads to element
gst_element_add_pad(GST_ELEMENT(filter),filter->srcpad);
gst_element_add_pad(GST_ELEMENT(filter), filter->sinkpad);

//set chain function for sink pad
gst_pad_set_chain_function(filter->sinkpad, gst_obt_filter_chain);

//set event function
gst_pad_set_event_function(filter->sinkpad, gst_obt_filter_event);

//set query function
gst_pad_set_query_function(filter->srcpad, gst_obt_filter_src_query);

filter->silent = FALSE;
}


/*
[plugin] plugin init Func
*/
static gboolean plugin_init(GstPlugin* plugin)
{
g_print("plugin_init\n");
gboolean ret;

//register plugin feature
//[todo]

//register element into plugin
ret = gst_element_register(plugin, "obtfilter", GST_RANK_MARGINAL, GST_TYPE_OBT_FILTER); // obtfilter will be the element name
//ret = gst_element_register(plugin, "ObtFilter_1", GST_RANK_MARGINAL, GST_TYPE_OBT_FILTER);

return ret;
}


/*
[plugin] export this plugin
define entry point #plugin_init and meta data
*/
GST_PLUGIN_DEFINE(
GST_VERSION_MAJOR, //specify the version of "gstreamer core" this plugin use, no need modification in gerenal
GST_VERSION_MINOR, //specify the version of "gstreamer core" this plugin use, no need modification in gerenal
obtplugin, //[!IMPORTANT] plugin short name , eg. gst-inspect --plugin obtplugin . BE CAREFUL !!! this name is ALSO the plugin file's name, eg. plugin file's name should be libobtplugin.so
//if plugin's name is not match to this value, plugin file will not be treated as a plugin, eg. gst-inspect --plugin libobt_plugin.so will be
//told "libobt_plugin.so is not a plugin"
"Obt filter plugin", //description
plugin_init, //plugin entry point
VERSION, //version
"LGPL", //license
"LocalPlugin", //under linux, which rpm package this plugin belong to
"n/a" //home page of current
)

/***************************************** boilerplate Funcs [END] *****************************************/


/***************************************** Local Funcs [START] *****************************************/

static GstBuffer *gst_obt_filter_process_data(GstObtFilter* filter,GstBuffer* buf)
{
//request GstBuffer
//get data from #buf
//process #buf to produce new data
//put new data into requested GstBuffer
//return requested GstBuffer
return buf;
}

static gboolean gst_obt_filter_stop_processing(GstObtFilter* filter)
{
//make current element to stop working
return TRUE;
}

/*
memory allocation during initialization
*/
static gboolean gst_obt_filter_allocate_memory(GstObtFilter* filter)
{
//allocate memory if needed
//load necessary run-time lib
return TRUE;
}

/*
memory deallocation during destruction
*/
static gboolean gst_obt_filter_free_memory(GstObtFilter* filter)
{
//unload loaded run-time lib
//release allocated memory
return TRUE;
}

/***************************************** Local Funcs [END] *****************************************/

编译及部署:

make_plugin:

gcc -g -fPIC -shared -I/usr/include/gstreamer-1.0 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include ObtFilter.c -o libobtplugin.so

install:

#!/bin/bash

sudo cp $1 /usr/lib/x86_64-linux-gnu/gstreamer-1.0/

使用:

./make_plugin
./install libobtplugin.so

配置环境变量:

如不做特殊说明,将环境变量写入 ~/.bashrc ,然后source ~/.bashrc,为了让其他终端也生效,在其他终端中也执行 source ~/.bashrc

1)GST_PLUGIN_PATH

如果plugin不部署到系统lib目录下,gst-inspect 会提示无法找到element。因此需要配置一个环境变量指向 插件所在目录。

export GST_PLUGIN_PATH=/home/ubuntu/_WORKSPACE/deps/gstreamer-1.18-all/lib/x86_64-linux-gnu/gstreamer-1.0

2)GST_PLUGIN_SCANNER

export GST_PLUGIN_SCANNER=/home/ubuntu/_WORKSPACE/deps/gstreamer-1.18-all/libexec/gstreamer-1.0/gst-plugin-scanner

注意:GST_PLUGIN_PATH 会影响gst_element_factory_make的查找,如果gst-inspect不能够找到element,那么同样地gst_element_factory_make也会创建失败。

网友评论