Created
May 27, 2021 07:36
-
-
Save silently/c3821dcf7b65767538378b445d0346e5 to your computer and use it in GitHub Desktop.
Simple GStreamer audio filter test
This file contains 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
gcc -Wall `pkg-config --cflags --libs gstreamer-audio-1.0` -fPIC -c plugin.c -o build/passthrough-plugin.o | |
gcc -Wall `pkg-config --cflags --libs gstreamer-audio-1.0` -fPIC -c passthrough.c -o build/passthrough.o | |
g++ -shared -Wall `pkg-config --cflags --libs gstreamer-audio-1.0` -lssl -lcrypto -o build/libpassthrough.so build/passthrough.o build/passthrough-plugin.o |
This file contains 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
#include <stdio.h> | |
#include <gst/gst.h> | |
#include <gst/base/gstbasetransform.h> | |
#include <gst/audio/audio.h> | |
#include <gst/audio/gstaudiofilter.h> | |
#include "passthrough.h" | |
#define GST_CAT_DEFAULT gst_passthrough_debug | |
GST_DEBUG_CATEGORY_STATIC(GST_CAT_DEFAULT); | |
enum | |
{ | |
PROP_0, | |
PROP_PARAM, | |
}; | |
#define ALLOWED_CAPS \ | |
"audio/x-raw, " \ | |
"format=(string) " GST_AUDIO_NE(F32) ", " \ | |
"rate=(int)[8000,MAX], " \ | |
"channels=(int)[1,MAX]" | |
G_DEFINE_TYPE(GstPassthrough, gst_passthrough, GST_TYPE_AUDIO_FILTER); | |
static void gst_passthrough_finalize(GObject *object); | |
static void gst_passthrough_set_property(GObject *object, guint prop_id, | |
const GValue *value, GParamSpec *pspec); | |
static void gst_passthrough_get_property(GObject *object, guint prop_id, | |
GValue *value, GParamSpec *pspec); | |
static gboolean gst_passthrough_setup(GstAudioFilter *filter, | |
const GstAudioInfo *info); | |
static GstFlowReturn gst_passthrough_transform_ip(GstBaseTransform *base, | |
GstBuffer *buf); | |
static void gst_passthrough_transform_float(GstPassthrough *filter, | |
gfloat *data, guint num_samples); | |
static GstElementClass *parent_class = NULL; | |
/* GObject vmethod implementations */ | |
static void | |
gst_passthrough_class_init(GstPassthroughClass *klass) | |
{ | |
GObjectClass *gobject_class; | |
GstElementClass *gstelement_class; | |
GstCaps *caps; | |
GST_DEBUG_CATEGORY_INIT(gst_passthrough_debug, "passthrough", 0, | |
"passthrough element"); | |
gobject_class = (GObjectClass *)klass; | |
gstelement_class = (GstElementClass *)klass; | |
parent_class = g_type_class_peek_parent(klass); | |
gobject_class->finalize = gst_passthrough_finalize; | |
gobject_class->set_property = gst_passthrough_set_property; | |
gobject_class->get_property = gst_passthrough_get_property; | |
g_object_class_install_property(gobject_class, PROP_PARAM, | |
g_param_spec_float("param", "Whatever param", | |
"Ignored at the moment", 0.0, 100.0, | |
1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE)); | |
gst_element_class_set_static_metadata(gstelement_class, "Passthrough", | |
"Filter/Effect/Audio", | |
"Passthrough", | |
"Passthrough"); | |
caps = gst_caps_from_string(ALLOWED_CAPS); | |
gst_audio_filter_class_add_pad_templates(GST_AUDIO_FILTER_CLASS(klass), | |
caps); | |
gst_caps_unref(caps); | |
GST_BASE_TRANSFORM_CLASS(klass)->transform_ip = | |
GST_DEBUG_FUNCPTR(gst_passthrough_transform_ip); | |
GST_BASE_TRANSFORM_CLASS(klass)->transform_ip_on_passthrough = FALSE; | |
GST_AUDIO_FILTER_CLASS(klass)->setup = | |
GST_DEBUG_FUNCPTR(gst_passthrough_setup); | |
} | |
static void | |
gst_passthrough_init(GstPassthrough *filter) | |
{ | |
printf("Init plugin\n"); | |
filter->param = 1.0; | |
gst_base_transform_set_in_place(GST_BASE_TRANSFORM(filter), TRUE); | |
gst_base_transform_set_gap_aware(GST_BASE_TRANSFORM(filter), TRUE); | |
} | |
static void | |
gst_passthrough_finalize(GObject *object) | |
{ | |
printf("Finalize plugin\n"); | |
G_OBJECT_CLASS(parent_class)->finalize(object); | |
} | |
static void | |
gst_passthrough_set_property(GObject *object, guint prop_id, | |
const GValue *value, GParamSpec *pspec) | |
{ | |
GstPassthrough *filter = GST_PASSTHROUGH(object); | |
switch (prop_id) | |
{ | |
case PROP_PARAM: | |
filter->param = g_value_get_float(value); | |
gst_base_transform_set_passthrough(GST_BASE_TRANSFORM(filter), filter->param == 1.0); | |
break; | |
default: | |
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); | |
break; | |
} | |
} | |
static void | |
gst_passthrough_get_property(GObject *object, guint prop_id, | |
GValue *value, GParamSpec *pspec) | |
{ | |
GstPassthrough *filter = GST_PASSTHROUGH(object); | |
switch (prop_id) | |
{ | |
case PROP_PARAM: | |
g_value_set_float(value, filter->param); | |
break; | |
default: | |
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); | |
break; | |
} | |
} | |
/* GstAudioFilter vmethod implementations */ | |
static gboolean | |
gst_passthrough_setup(GstAudioFilter *base, const GstAudioInfo *info) | |
{ | |
GstPassthrough *filter = GST_PASSTHROUGH(base); | |
gboolean ret = TRUE; | |
switch (GST_AUDIO_INFO_FORMAT(info)) | |
{ | |
case GST_AUDIO_FORMAT_F32: | |
filter->process = (GstPassthroughProcessFunc) gst_passthrough_transform_float; | |
break; | |
default: | |
ret = FALSE; | |
break; | |
} | |
return ret; | |
} | |
static void | |
gst_passthrough_transform_float(GstPassthrough *filter, | |
gfloat *data, guint num_samples) | |
{ | |
// -> may do something here to implement an audio effect | |
// gfloat *copy = malloc(num_samples * sizeof(*copy)); | |
// memcpy(copy, data, sizeof(*copy) * num_samples); | |
// free(copy); | |
} | |
/* GstBaseTransform vmethod implementations */ | |
static GstFlowReturn | |
gst_passthrough_transform_ip(GstBaseTransform *base, GstBuffer *buf) | |
{ | |
GstPassthrough *filter = GST_PASSTHROUGH(base); | |
guint num_samples; | |
GstClockTime timestamp, stream_time; | |
GstMapInfo map; | |
timestamp = GST_BUFFER_TIMESTAMP(buf); | |
stream_time = | |
gst_segment_to_stream_time(&base->segment, GST_FORMAT_TIME, timestamp); | |
GST_DEBUG_OBJECT(filter, "sync to %" GST_TIME_FORMAT, | |
GST_TIME_ARGS(timestamp)); | |
if (GST_CLOCK_TIME_IS_VALID(stream_time)) | |
gst_object_sync_values(GST_OBJECT(filter), stream_time); | |
if (G_UNLIKELY(GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_GAP))) | |
return GST_FLOW_OK; | |
gst_buffer_map(buf, &map, GST_MAP_READWRITE); | |
num_samples = map.size / GST_AUDIO_FILTER_BPS(filter); | |
filter->process(filter, map.data, num_samples); | |
gst_buffer_unmap(buf, &map); | |
return GST_FLOW_OK; | |
} |
This file contains 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
#ifndef __GST_PASSTHROUGH_H__ | |
#define __GST_PASSTHROUGH_H__ | |
#include <gst/gst.h> | |
#include <gst/base/gstbasetransform.h> | |
#include <gst/audio/audio.h> | |
#include <gst/audio/gstaudiofilter.h> | |
G_BEGIN_DECLS | |
#define GST_TYPE_PASSTHROUGH (gst_passthrough_get_type()) | |
#define GST_PASSTHROUGH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_PASSTHROUGH, GstPassthrough)) | |
#define GST_IS_PASSTHROUGH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_PASSTHROUGH)) | |
#define GST_PASSTHROUGH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_PASSTHROUGH, GstPassthroughClass)) | |
#define GST_IS_PASSTHROUGH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_PASSTHROUGH)) | |
#define GST_PASSTHROUGH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_PASSTHROUGH, GstPassthroughClass)) | |
typedef struct _GstPassthrough GstPassthrough; | |
typedef struct _GstPassthroughClass GstPassthroughClass; | |
typedef void (*GstPassthroughProcessFunc)(GstPassthrough *, guint8 *, guint); | |
struct _GstPassthrough | |
{ | |
GstAudioFilter audiofilter; | |
gfloat param; | |
/* < private > */ | |
GstPassthroughProcessFunc process; | |
}; | |
struct _GstPassthroughClass | |
{ | |
GstAudioFilterClass parent; | |
}; | |
GType gst_passthrough_get_type(void); | |
G_END_DECLS | |
#endif /* __GST_PASSTHROUGH_H__ */ |
This file contains 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
#include <gst/gst.h> | |
#include "passthrough.h" | |
static gboolean | |
plugin_init (GstPlugin * plugin) | |
{ | |
gboolean ret = FALSE; | |
ret |= gst_element_register (plugin, "passthrough", GST_RANK_NONE, GST_TYPE_PASSTHROUGH); | |
return ret; | |
} | |
#ifndef VERSION | |
#define VERSION "0.1" | |
#endif | |
#ifndef PACKAGE | |
#define PACKAGE "passthrough" | |
#endif | |
#ifndef PACKAGE_NAME | |
#define PACKAGE_NAME "passthrough" | |
#endif | |
#ifndef GST_PACKAGE_ORIGIN | |
#define GST_PACKAGE_ORIGIN "passthrough" | |
#endif | |
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, | |
GST_VERSION_MINOR, | |
passthrough, | |
"passthrough", | |
plugin_init, VERSION, "LGPL", PACKAGE_NAME, GST_PACKAGE_ORIGIN) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment