[GStreamer] 插件编写 filter element

本文详细介绍了一个GStreamer插件的源码实现过程,包括插件的结构、关键函数定义与实现、状态转换处理等内容,并提供了编译部署指导。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

源码:

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/

或者

#!/bin/bash

export GST_PLUGIN_PATH=$GST_PLUGIN_PATH:[so文件所在路径]

使用:

./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也会创建失败。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值