From 77a7c4c8fbc7a9fb59039c0f9469923dd651c009 Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Mon, 4 Jul 2005 14:02:46 +0000 Subject: [PATCH] examples/level/: Examples moved out of the source dir. Not updated tho. Original commit message from CVS: 2005-07-04 Andy Wingo * examples/level/: * examples/level/Makefile.am: * examples/level/README: * examples/level/demo.c: * examples/level/plot.c: Examples moved out of the source dir. Not updated tho. * configure.ac: Add level to the build. * gst/level/Makefile.am: * gst/level/gstlevel.h: * gst/level/gstlevel.c: Cleaned up, ported to 0.9. --- ChangeLog | 13 + configure.ac | 7 +- examples/Makefile.am | 4 +- examples/level/Makefile.am | 11 + {gst => examples}/level/README | 0 {gst => examples}/level/demo.c | 0 {gst => examples}/level/plot.c | 0 gst/level/Makefile.am | 30 +- gst/level/filter.func | 41 --- gst/level/gstlevel-marshal.list | 1 - gst/level/gstlevel.c | 514 ++++++++++++++++++----------------- gst/level/gstlevel.h | 23 +- tests/old/examples/Makefile.am | 4 +- tests/old/examples/level/Makefile.am | 11 + tests/old/examples/level/README | 39 +++ tests/old/examples/level/demo.c | 155 +++++++++++ tests/old/examples/level/plot.c | 123 +++++++++ 17 files changed, 638 insertions(+), 338 deletions(-) create mode 100644 examples/level/Makefile.am rename {gst => examples}/level/README (100%) rename {gst => examples}/level/demo.c (100%) rename {gst => examples}/level/plot.c (100%) delete mode 100644 gst/level/filter.func delete mode 100644 gst/level/gstlevel-marshal.list create mode 100644 tests/old/examples/level/Makefile.am create mode 100644 tests/old/examples/level/README create mode 100644 tests/old/examples/level/demo.c create mode 100644 tests/old/examples/level/plot.c diff --git a/ChangeLog b/ChangeLog index 2ed7986..b07e938 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,19 @@ 2005-07-04 Andy Wingo + * examples/level/: + * examples/level/Makefile.am: + * examples/level/README: + * examples/level/demo.c: + * examples/level/plot.c: Examples moved out of the source dir. Not + updated tho. + + * configure.ac: Add level to the build. + + * gst/level/Makefile.am: + * gst/level/gstlevel.h: + * gst/level/gstlevel.c: Cleaned up, ported to 0.9. + * ext/aalib/gstaasink.c (gst_aasink_fixate): Update for newer fixate prototype. diff --git a/configure.ac b/configure.ac index c58f654..6acad33 100644 --- a/configure.ac +++ b/configure.ac @@ -297,15 +297,17 @@ dnl these are all the gst plug-ins, compilable without additional libs GST_PLUGINS_ALL="\ alpha \ avi \ - videofilter \ effectv \ goom \ law \ + level \ realmedia \ rtp \ rtsp \ smpte \ - udp" + udp \ + videofilter \ + " dnl see if we can build C++ plug-ins if test "x$HAVE_CXX" = "xyes"; then @@ -489,6 +491,7 @@ gst/avi/Makefile gst/effectv/Makefile gst/goom/Makefile gst/law/Makefile +gst/level/Makefile gst/realmedia/Makefile gst/rtp/Makefile gst/rtsp/Makefile diff --git a/examples/Makefile.am b/examples/Makefile.am index 0c8190c..11f9222 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -5,7 +5,7 @@ FT2_SUBDIRS= endif if HAVE_GTK -GTK_SUBDIRS=dynparams $(FT2_SUBDIRS) +GTK_SUBDIRS=dynparams level $(FT2_SUBDIRS) else GTK_SUBDIRS= endif @@ -17,4 +17,4 @@ GCONF_SUBDIRS= endif SUBDIRS=$(GTK_SUBDIRS) $(GCONF_SUBDIRS) switch -DIST_SUBDIRS=capsfilter dynparams seeking indexing gstplay switch +DIST_SUBDIRS=capsfilter dynparams seeking indexing gstplay switch level diff --git a/examples/level/Makefile.am b/examples/level/Makefile.am new file mode 100644 index 0000000..bf76136 --- /dev/null +++ b/examples/level/Makefile.am @@ -0,0 +1,11 @@ +noinst_PROGRAMS = demo plot + +demo_SOURCES = demo.c +demo_CFLAGS = $(GTK_CFLAGS) $(GST_CFLAGS) +demo_LDFLAGS = $(GTK_LIBS) $(GST_LIBS) + +plot_SOURCES = plot.c +plot_CFLAGS = $(GTK_CFLAGS) $(GST_CFLAGS) +plot_LDFLAGS = $(GTK_LIBS) $(GST_LIBS) + +EXTRA_DIST = README diff --git a/gst/level/README b/examples/level/README similarity index 100% rename from gst/level/README rename to examples/level/README diff --git a/gst/level/demo.c b/examples/level/demo.c similarity index 100% rename from gst/level/demo.c rename to examples/level/demo.c diff --git a/gst/level/plot.c b/examples/level/plot.c similarity index 100% rename from gst/level/plot.c rename to examples/level/plot.c diff --git a/gst/level/Makefile.am b/gst/level/Makefile.am index 43ef181..5bed77d 100644 --- a/gst/level/Makefile.am +++ b/gst/level/Makefile.am @@ -1,34 +1,8 @@ plugin_LTLIBRARIES = libgstlevel.la -# variables used for enum/marshal generation -glib_enum_define = GST_LEVEL -glib_enum_prefix = gst_level - -include $(top_srcdir)/common/glib-gen.mak - -built_sources = gstlevel-marshal.c -built_headers = gstlevel-marshal.h - -BUILT_SOURCES = $(built_sources) $(built_headers) - libgstlevel_la_SOURCES = gstlevel.c -nodist_libgstlevel_la_SOURCES = $(built_sources) libgstlevel_la_CFLAGS = $(GST_CFLAGS) -libgstlevel_la_LIBADD = +libgstlevel_la_LIBADD = $(GST_BASE_LIBS) libgstlevel_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -noinst_HEADERS = gstlevel.h filter.func - -if HAVE_GTK -noinst_PROGRAMS = demo plot -demo_SOURCES = demo.c -demo_CFLAGS = $(GTK_CFLAGS) $(GST_CFLAGS) -demo_LDFLAGS = $(GTK_LIBS) $(GST_LIBS) -plot_SOURCES = plot.c -plot_CFLAGS = $(GTK_CFLAGS) $(GST_CFLAGS) -plot_LDFLAGS = $(GTK_LIBS) $(GST_LIBS) -endif - -CLEANFILES = $(BUILT_SOURCES) - -EXTRA_DIST = README gstlevel-marshal.list +noinst_HEADERS = gstlevel.h diff --git a/gst/level/filter.func b/gst/level/filter.func deleted file mode 100644 index fd82c03..0000000 --- a/gst/level/filter.func +++ /dev/null @@ -1,41 +0,0 @@ -/* -static void inline -gst_level_fast_16bit_chain (gint16 * in, guint num, gint channels, - gint resolution, double *CS, double *peak) -*/ -/* process one (interleaved) channel of incoming samples - * calculate square sum of samples - * normalize and return normalized Cumulative Square - * caller must assure num is a multiple of channels - * this filter only accepts signed audio data, so mid level is always 0 - */ -{ - register int j; - double squaresum = 0.0; /* square sum of the integer samples */ - register double square = 0.0; /* Square */ - register double PSS = 0.0; /* Peak Square Sample */ - gdouble normalizer; - - *CS = 0.0; /* Cumulative Square for this block */ - - normalizer = (double) (1 << resolution); - - /* - * process data here - * input sample data enters in *in_data as 8 or 16 bit data - * samples for left and right channel are interleaved - * returns the Mean Square of the samples as a double between 0 and 1 - */ - - for (j = 0; j < num; j += channels) - { - //g_print ("ch %d -> smp %d\n", j, in[j]); - square = (double) (in[j] * in[j]); - if (square > PSS) PSS = square; - squaresum += square; - } - *peak = PSS / ((double) normalizer * (double) normalizer); - - /* return normalized cumulative square */ - *CS = squaresum / ((double) normalizer * (double) normalizer); -} diff --git a/gst/level/gstlevel-marshal.list b/gst/level/gstlevel-marshal.list deleted file mode 100644 index 9a2455b..0000000 --- a/gst/level/gstlevel-marshal.list +++ /dev/null @@ -1 +0,0 @@ -VOID:DOUBLE,INT,DOUBLE,DOUBLE,DOUBLE diff --git a/gst/level/gstlevel.c b/gst/level/gstlevel.c index e1a3bb5..12cc820 100644 --- a/gst/level/gstlevel.c +++ b/gst/level/gstlevel.c @@ -25,14 +25,12 @@ #include "config.h" #endif #include -#include #include "gstlevel.h" #include "math.h" GST_DEBUG_CATEGORY (level_debug); #define GST_CAT_DEFAULT level_debug -/* elementfactory information */ static GstElementDetails level_details = { "Level", "Filter/Analyzer/Audio", @@ -40,8 +38,6 @@ static GstElementDetails level_details = { "Thomas " }; -/* pad templates */ - static GstStaticPadTemplate sink_template_factory = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, @@ -66,87 +62,170 @@ GST_STATIC_PAD_TEMPLATE ("src", "depth = (int) { 8, 16 }, " "signed = (boolean) true") ); -/* Filter signals and args */ -enum -{ - /* FILL ME */ - SIGNAL_LEVEL, - LAST_SIGNAL -}; enum { - ARG_0, - ARG_SIGNAL_LEVEL, - ARG_SIGNAL_INTERVAL, - ARG_PEAK_TTL, - ARG_PEAK_FALLOFF + PROP_0, + PROP_SIGNAL_LEVEL, + PROP_SIGNAL_INTERVAL, + PROP_PEAK_TTL, + PROP_PEAK_FALLOFF }; -static void gst_level_class_init (GstLevelClass * klass); -static void gst_level_base_init (GstLevelClass * klass); -static void gst_level_init (GstLevel * filter); + +GST_BOILERPLATE (GstLevel, gst_level, GstBaseTransform, + GST_TYPE_BASE_TRANSFORM); + static void gst_level_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_level_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static void gst_level_chain (GstPad * pad, GstData * _data); +static gboolean gst_level_set_caps (GstBaseTransform * trans, GstCaps * in, + GstCaps * out); +static GstFlowReturn gst_level_transform (GstBaseTransform * trans, + GstBuffer * in, GstBuffer ** out); + + +static void +gst_level_base_init (gpointer g_class) +{ + GstElementClass *element_class = g_class; + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sink_template_factory)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&src_template_factory)); + gst_element_class_set_details (element_class, &level_details); +} + +static void +gst_level_class_init (GstLevelClass * klass) +{ + GObjectClass *gobject_class; + GstBaseTransformClass *trans_class; + + gobject_class = (GObjectClass *) klass; + trans_class = (GstBaseTransformClass *) klass; + + gobject_class->set_property = gst_level_set_property; + gobject_class->get_property = gst_level_get_property; + + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SIGNAL_LEVEL, + g_param_spec_boolean ("signal", "Signal", + "Emit level signals for each interval", TRUE, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SIGNAL_INTERVAL, + g_param_spec_double ("interval", "Interval", + "Interval between emissions (in seconds)", + 0.01, 100.0, 0.1, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PEAK_TTL, + g_param_spec_double ("peak_ttl", "Peak TTL", + "Time To Live of decay peak before it falls back", + 0, 100.0, 0.3, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PEAK_FALLOFF, + g_param_spec_double ("peak_falloff", "Peak Falloff", + "Decay rate of decay peak after TTL (in dB/sec)", + 0.0, G_MAXDOUBLE, 10.0, G_PARAM_READWRITE)); + + GST_DEBUG_CATEGORY_INIT (level_debug, "level", 0, "Level calculation"); + + trans_class->set_caps = gst_level_set_caps; + trans_class->transform = gst_level_transform; +} + +static void +gst_level_init (GstLevel * filter) +{ + filter->CS = NULL; + filter->peak = NULL; + filter->MS = NULL; + filter->RMS_dB = NULL; + + filter->rate = 0; + filter->width = 0; + filter->channels = 0; + + filter->interval = 0.1; + filter->decay_peak_ttl = 0.4; + filter->decay_peak_falloff = 10.0; /* dB falloff (/sec) */ +} + +static void +gst_level_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstLevel *filter = GST_LEVEL (object); -static GstElementClass *parent_class = NULL; -static guint gst_filter_signals[LAST_SIGNAL] = { 0 }; + switch (prop_id) { + case PROP_SIGNAL_LEVEL: + filter->signal = g_value_get_boolean (value); + break; + case PROP_SIGNAL_INTERVAL: + filter->interval = g_value_get_double (value); + break; + case PROP_PEAK_TTL: + filter->decay_peak_ttl = g_value_get_double (value); + break; + case PROP_PEAK_FALLOFF: + filter->decay_peak_falloff = g_value_get_double (value); + break; + default: + break; + } +} -GType -gst_level_get_type (void) +static void +gst_level_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) { - static GType level_type = 0; - - if (!level_type) { - static const GTypeInfo level_info = { - sizeof (GstLevelClass), - (GBaseInitFunc) gst_level_base_init, NULL, - (GClassInitFunc) gst_level_class_init, NULL, NULL, - sizeof (GstLevel), 0, - (GInstanceInitFunc) gst_level_init - }; - - level_type = g_type_register_static (GST_TYPE_ELEMENT, "GstLevel", - &level_info, 0); + GstLevel *filter = GST_LEVEL (object); + + switch (prop_id) { + case PROP_SIGNAL_LEVEL: + g_value_set_boolean (value, filter->signal); + break; + case PROP_SIGNAL_INTERVAL: + g_value_set_double (value, filter->interval); + break; + case PROP_PEAK_TTL: + g_value_set_double (value, filter->decay_peak_ttl); + break; + case PROP_PEAK_FALLOFF: + g_value_set_double (value, filter->decay_peak_falloff); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; } - return level_type; } -static GstPadLinkReturn -gst_level_link (GstPad * pad, const GstCaps * caps) +static gint +structure_get_int (GstStructure * structure, const gchar * field) +{ + gint ret; + + if (!gst_structure_get_int (structure, field, &ret)) + g_assert_not_reached (); + + return ret; +} + +static gboolean +gst_level_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out) { GstLevel *filter; - GstPad *otherpad; - GstPadLinkReturn res; GstStructure *structure; int i; - gboolean ret; - filter = GST_LEVEL (gst_pad_get_parent (pad)); - g_return_val_if_fail (filter != NULL, GST_PAD_LINK_REFUSED); - g_return_val_if_fail (GST_IS_LEVEL (filter), GST_PAD_LINK_REFUSED); - otherpad = (pad == filter->srcpad ? filter->sinkpad : filter->srcpad); - - res = gst_pad_try_set_caps (otherpad, caps); - /* if ok, set filter */ - if (res != GST_PAD_LINK_OK && res != GST_PAD_LINK_DONE) { - return res; - } + filter = GST_LEVEL (trans); filter->num_samples = 0; - structure = gst_caps_get_structure (caps, 0); - ret = gst_structure_get_int (structure, "rate", &filter->rate); - ret &= gst_structure_get_int (structure, "width", &filter->width); - ret &= gst_structure_get_int (structure, "channels", &filter->channels); - - if (!ret) - return GST_PAD_LINK_REFUSED; + structure = gst_caps_get_structure (in, 0); + filter->rate = structure_get_int (structure, "rate"); + filter->width = structure_get_int (structure, "width"); + filter->channels = structure_get_int (structure, "channels"); /* allocate channel variable arrays */ g_free (filter->CS); @@ -170,61 +249,129 @@ gst_level_link (GstPad * pad, const GstCaps * caps) filter->MS[i] = filter->RMS_dB[i] = 0.0; } - return GST_PAD_LINK_OK; + return TRUE; +} + +#if 0 +#define DEBUG(str,...) g_print (str, ...) +#else +#define DEBUG(str,...) /*nop */ +#endif + +/* process one (interleaved) channel of incoming samples + * calculate square sum of samples + * normalize and return normalized Cumulative Square + * caller must assure num is a multiple of channels + * this filter only accepts signed audio data, so mid level is always 0 + */ +#define DEFINE_LEVEL_CALCULATOR(TYPE) \ +static void inline \ +gst_level_calculate_##TYPE (TYPE * in, guint num, gint channels, \ + gint resolution, double *CS, double *peak) \ +{ \ + register int j; \ + double squaresum = 0.0; /* square sum of the integer samples */ \ + register double square = 0.0; /* Square */ \ + register double PSS = 0.0; /* Peak Square Sample */ \ + gdouble normalizer; \ + \ + *CS = 0.0; /* Cumulative Square for this block */ \ + \ + normalizer = (double) (1 << resolution); \ + \ + /* \ + * process data here \ + * input sample data enters in *in_data as 8 or 16 bit data \ + * samples for left and right channel are interleaved \ + * returns the Mean Square of the samples as a double between 0 and 1 \ + */ \ + \ + for (j = 0; j < num; j += channels) \ + { \ + DEBUG ("ch %d -> smp %d\n", j, in[j]); \ + square = (double) (in[j] * in[j]); \ + if (square > PSS) PSS = square; \ + squaresum += square; \ + } \ + *peak = PSS / ((double) normalizer * (double) normalizer); \ + \ + /* return normalized cumulative square */ \ + *CS = squaresum / ((double) normalizer * (double) normalizer); \ } -static void inline -gst_level_fast_16bit_chain (gint16 * in, guint num, gint channels, - gint resolution, double *CS, double *peak) -#include "filter.func" - static void inline - gst_level_fast_8bit_chain (gint8 * in, guint num, gint channels, - gint resolution, double *CS, double *peak) -#include "filter.func" - static void gst_level_chain (GstPad * pad, GstData * _data) +DEFINE_LEVEL_CALCULATOR (gint16); +DEFINE_LEVEL_CALCULATOR (gint8); + +static GstMessage * +gst_level_message_new (GstLevel * l, gdouble endtime) { - GstBuffer *buf = GST_BUFFER (_data); - GstLevel *filter; - gint16 *in_data; + GstStructure *s; + GValue v = { 0, }; + + g_value_init (&v, GST_TYPE_LIST); + + s = gst_structure_new ("level", "endtime", G_TYPE_DOUBLE, endtime, NULL); + /* will copy-by-value */ + gst_structure_set_value (s, "rms", &v); + gst_structure_set_value (s, "peak", &v); + gst_structure_set_value (s, "decay", &v); + + return gst_message_new_application (GST_OBJECT (l), s); +} +static void +gst_level_message_append_channel (GstMessage * m, gdouble rms, gdouble peak, + gdouble decay) +{ + GstStructure *s; + GValue v = { 0, }; + GValue *l; + + g_value_init (&v, G_TYPE_DOUBLE); + + s = (GstStructure *) gst_message_get_structure (m); + + l = (GValue *) gst_structure_get_value (s, "rms"); + g_value_set_double (&v, rms); + gst_value_list_append_value (l, &v); /* copies by value */ + + l = (GValue *) gst_structure_get_value (s, "peak"); + g_value_set_double (&v, peak); + gst_value_list_append_value (l, &v); /* copies by value */ + + l = (GValue *) gst_structure_get_value (s, "decay"); + g_value_set_double (&v, decay); + gst_value_list_append_value (l, &v); /* copies by value */ +} + +static GstFlowReturn +gst_level_transform (GstBaseTransform * trans, GstBuffer * in, GstBuffer ** out) +{ + GstLevel *filter; + gpointer in_data; double CS = 0.0; gint num_samples = 0; gint i; - g_return_if_fail (pad != NULL); - g_return_if_fail (GST_IS_PAD (pad)); - g_return_if_fail (buf != NULL); - - filter = GST_LEVEL (GST_OBJECT_PARENT (pad)); - g_return_if_fail (filter != NULL); - g_return_if_fail (GST_IS_LEVEL (filter)); - - if (!gst_pad_is_negotiated (pad)) { - GST_ELEMENT_ERROR (filter, CORE, NEGOTIATION, (NULL), - ("sinkpad not negotiated")); - gst_data_unref (_data); - return; - } + filter = GST_LEVEL (trans); for (i = 0; i < filter->channels; ++i) filter->CS[i] = filter->peak[i] = filter->MS[i] = filter->RMS_dB[i] = 0.0; - in_data = (gint16 *) GST_BUFFER_DATA (buf); + in_data = GST_BUFFER_DATA (in); + num_samples = GST_BUFFER_SIZE (in) / (filter->width / 8); - /* total number of interleaved samples */ - num_samples = GST_BUFFER_SIZE (buf) / (filter->width / 8); - if (num_samples % filter->channels != 0) - g_warning - ("WARNING: level: programming error, data not properly interleaved"); + g_return_val_if_fail (num_samples % filter->channels == 0, + GST_FLOW_UNEXPECTED); for (i = 0; i < filter->channels; ++i) { switch (filter->width) { case 16: - gst_level_fast_16bit_chain (in_data + i, num_samples, + gst_level_calculate_gint16 (in_data + i, num_samples, filter->channels, filter->width - 1, &CS, &filter->peak[i]); break; case 8: - gst_level_fast_8bit_chain (((gint8 *) in_data) + i, num_samples, + gst_level_calculate_gint8 (((gint8 *) in_data) + i, num_samples, filter->channels, filter->width - 1, &CS, &filter->peak[i]); break; } @@ -233,21 +380,20 @@ gst_level_fast_16bit_chain (gint16 * in, guint num, gint channels, filter->CS[i] += CS; } - gst_pad_push (filter->srcpad, GST_DATA (buf)); filter->num_samples += num_samples; for (i = 0; i < filter->channels; ++i) { filter->decay_peak_age[i] += num_samples; - /* g_print ("filter peak info [%d]: peak %f, age %f\n", i, - filter->last_peak[i], filter->decay_peak_age[i]); */ + DEBUG ("filter peak info [%d]: peak %f, age %f\n", i, + filter->last_peak[i], filter->decay_peak_age[i]); /* update running peak */ if (filter->peak[i] > filter->last_peak[i]) filter->last_peak[i] = filter->peak[i]; /* update decay peak */ if (filter->peak[i] >= filter->decay_peak[i]) { - /* g_print ("new peak, %f\n", filter->peak[i]); */ + DEBUG ("new peak, %f\n", filter->peak[i]); filter->decay_peak[i] = filter->peak[i]; filter->decay_peak_age[i] = 0; } else { @@ -262,11 +408,11 @@ gst_level_fast_16bit_chain (gint16 * in, guint num, gint channels, falloff_dB = filter->decay_peak_falloff * length; falloff = pow (10, falloff_dB / -20.0); - /* g_print ("falloff: length %f, dB falloff %f, falloff factor %e\n", - length, falloff_dB, falloff); */ + DEBUG ("falloff: length %f, dB falloff %f, falloff factor %e\n", + length, falloff_dB, falloff); filter->decay_peak[i] *= falloff; - /* g_print ("peak is %f samples old, decayed with factor %e to %f\n", - filter->decay_peak_age[i], falloff, filter->decay_peak[i]); */ + DEBUG ("peak is %f samples old, decayed with factor %e to %f\n", + filter->decay_peak_age[i], falloff, filter->decay_peak[i]); } } } @@ -275,164 +421,34 @@ gst_level_fast_16bit_chain (gint16 * in, guint num, gint channels, if (filter->num_samples >= filter->interval * (gdouble) filter->rate) { if (filter->signal) { - gdouble RMS, peak, endtime; + GstMessage *m; + double endtime, RMS; + + endtime = (double) GST_BUFFER_TIMESTAMP (in) / GST_SECOND + + (double) num_samples / (double) filter->rate; + + m = gst_level_message_new (filter, endtime); for (i = 0; i < filter->channels; ++i) { RMS = sqrt (filter->CS[i] / (filter->num_samples / filter->channels)); - peak = filter->last_peak[i]; - num_samples = GST_BUFFER_SIZE (buf) / (filter->width / 8); - endtime = (double) GST_BUFFER_TIMESTAMP (buf) / GST_SECOND - + (double) num_samples / (double) filter->rate; - - g_signal_emit (G_OBJECT (filter), gst_filter_signals[SIGNAL_LEVEL], 0, - endtime, i, - 20 * log10 (RMS), 20 * log10 (filter->last_peak[i]), + + gst_level_message_append_channel (m, 20 * log10 (RMS), + 20 * log10 (filter->last_peak[i]), 20 * log10 (filter->decay_peak[i])); - /* we emitted, so reset cumulative and normal peak */ + + /* reset cumulative and normal peak */ filter->CS[i] = 0.0; filter->last_peak[i] = 0.0; } + + gst_element_post_message (GST_ELEMENT (filter), m); } filter->num_samples = 0; } -} - -static void -gst_level_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstLevel *filter; - - g_return_if_fail (GST_IS_LEVEL (object)); - filter = GST_LEVEL (object); - - switch (prop_id) { - case ARG_SIGNAL_LEVEL: - filter->signal = g_value_get_boolean (value); - break; - case ARG_SIGNAL_INTERVAL: - filter->interval = g_value_get_double (value); - break; - case ARG_PEAK_TTL: - filter->decay_peak_ttl = g_value_get_double (value); - break; - case ARG_PEAK_FALLOFF: - filter->decay_peak_falloff = g_value_get_double (value); - break; - default: - break; - } -} - -static void -gst_level_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstLevel *filter; - - g_return_if_fail (GST_IS_LEVEL (object)); - filter = GST_LEVEL (object); - - switch (prop_id) { - case ARG_SIGNAL_LEVEL: - g_value_set_boolean (value, filter->signal); - break; - case ARG_SIGNAL_INTERVAL: - g_value_set_double (value, filter->interval); - break; - case ARG_PEAK_TTL: - g_value_set_double (value, filter->decay_peak_ttl); - break; - case ARG_PEAK_FALLOFF: - g_value_set_double (value, filter->decay_peak_falloff); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} -static void -gst_level_base_init (GstLevelClass * klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&sink_template_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&src_template_factory)); - gst_element_class_set_details (element_class, &level_details); -} + *out = in; -static void -gst_level_class_init (GstLevelClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - - parent_class = g_type_class_ref (GST_TYPE_ELEMENT); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIGNAL_LEVEL, - g_param_spec_boolean ("signal", "Signal", - "Emit level signals for each interval", TRUE, G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIGNAL_INTERVAL, - g_param_spec_double ("interval", "Interval", - "Interval between emissions (in seconds)", - 0.01, 100.0, 0.1, G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PEAK_TTL, - g_param_spec_double ("peak_ttl", "Peak TTL", - "Time To Live of decay peak before it falls back", - 0, 100.0, 0.3, G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PEAK_FALLOFF, - g_param_spec_double ("peak_falloff", "Peak Falloff", - "Decay rate of decay peak after TTL (in dB/sec)", - 0.0, G_MAXDOUBLE, 10.0, G_PARAM_READWRITE)); - - gobject_class->set_property = gst_level_set_property; - gobject_class->get_property = gst_level_get_property; - - gst_filter_signals[SIGNAL_LEVEL] = - g_signal_new ("level", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstLevelClass, level), NULL, NULL, - gst_level_marshal_VOID__DOUBLE_INT_DOUBLE_DOUBLE_DOUBLE, - G_TYPE_NONE, 5, - G_TYPE_DOUBLE, G_TYPE_INT, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE); - - GST_DEBUG_CATEGORY_INIT (level_debug, "level", 0, "Level calculation"); -} - -static void -gst_level_init (GstLevel * filter) -{ - filter->sinkpad = - gst_pad_new_from_template (gst_static_pad_template_get - (&sink_template_factory), "sink"); - gst_pad_set_link_function (filter->sinkpad, gst_level_link); - gst_pad_set_getcaps_function (filter->sinkpad, gst_pad_proxy_getcaps); - gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad); - gst_pad_set_chain_function (filter->sinkpad, gst_level_chain); - - filter->srcpad = - gst_pad_new_from_template (gst_static_pad_template_get - (&src_template_factory), "src"); - gst_pad_set_link_function (filter->srcpad, gst_level_link); - gst_pad_set_getcaps_function (filter->srcpad, gst_pad_proxy_getcaps); - gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad); - - filter->CS = NULL; - filter->peak = NULL; - filter->MS = NULL; - filter->RMS_dB = NULL; - - filter->rate = 0; - filter->width = 0; - filter->channels = 0; - - filter->interval = 0.1; - filter->decay_peak_ttl = 0.4; - filter->decay_peak_falloff = 10.0; /* dB falloff (/sec) */ + return GST_FLOW_OK; } static gboolean diff --git a/gst/level/gstlevel.h b/gst/level/gstlevel.h index 59427c7..a707238 100644 --- a/gst/level/gstlevel.h +++ b/gst/level/gstlevel.h @@ -27,12 +27,10 @@ #include +#include -#include "gstlevel-marshal.h" -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ +G_BEGIN_DECLS #define GST_TYPE_LEVEL \ @@ -46,13 +44,14 @@ extern "C" { #define GST_IS_LEVEL_CLASS(obj) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_LEVEL)) + typedef struct _GstLevel GstLevel; typedef struct _GstLevelClass GstLevelClass; + struct _GstLevel { - GstElement element; + GstBaseTransform element; - GstPad *sinkpad, *srcpad; gboolean signal; /* whether or not to emit signals */ gdouble interval; /* how many seconds between emits */ @@ -75,16 +74,14 @@ struct _GstLevel { }; struct _GstLevelClass { - GstElementClass parent_class; - void (*level) (GstElement *element, gdouble time, gint channel, - gdouble RMS_dB, gdouble peak_dB, gdouble decay_peak_dB); + GstBaseTransformClass parent_class; }; + GType gst_level_get_type(void); -#ifdef __cplusplus -} -#endif /* __cplusplus */ + +G_END_DECLS -#endif /* __GST_STEREO_H__ */ +#endif /* __GST_LEVEL_H__ */ diff --git a/tests/old/examples/Makefile.am b/tests/old/examples/Makefile.am index 0c8190c..11f9222 100644 --- a/tests/old/examples/Makefile.am +++ b/tests/old/examples/Makefile.am @@ -5,7 +5,7 @@ FT2_SUBDIRS= endif if HAVE_GTK -GTK_SUBDIRS=dynparams $(FT2_SUBDIRS) +GTK_SUBDIRS=dynparams level $(FT2_SUBDIRS) else GTK_SUBDIRS= endif @@ -17,4 +17,4 @@ GCONF_SUBDIRS= endif SUBDIRS=$(GTK_SUBDIRS) $(GCONF_SUBDIRS) switch -DIST_SUBDIRS=capsfilter dynparams seeking indexing gstplay switch +DIST_SUBDIRS=capsfilter dynparams seeking indexing gstplay switch level diff --git a/tests/old/examples/level/Makefile.am b/tests/old/examples/level/Makefile.am new file mode 100644 index 0000000..bf76136 --- /dev/null +++ b/tests/old/examples/level/Makefile.am @@ -0,0 +1,11 @@ +noinst_PROGRAMS = demo plot + +demo_SOURCES = demo.c +demo_CFLAGS = $(GTK_CFLAGS) $(GST_CFLAGS) +demo_LDFLAGS = $(GTK_LIBS) $(GST_LIBS) + +plot_SOURCES = plot.c +plot_CFLAGS = $(GTK_CFLAGS) $(GST_CFLAGS) +plot_LDFLAGS = $(GTK_LIBS) $(GST_LIBS) + +EXTRA_DIST = README diff --git a/tests/old/examples/level/README b/tests/old/examples/level/README new file mode 100644 index 0000000..0ae8418 --- /dev/null +++ b/tests/old/examples/level/README @@ -0,0 +1,39 @@ +level plugin by thomas + +this plugin signals: + - running time since last EOS/start + - channel + - RMS level + - peak level + - decaying peak level +over the given interval. + +This is useful for a VU meter display and for plotting out the signal graph. +The VU meter can either display RMS, or display immediate peak level and +have the falloff decaying peak level displayed as a line. + +The interval for signal emission, ttl of decay peak, and falloff of decay peak +can all be set. + +The element only takes unsigned data in; it could be extended to signed as +well, if separate fast chain functions are made that displaces the incoming +data to its midpoint (ie, 0,65535 should be mapped to -32768, 32767) + +There are two demo apps, apps and plot. apps will create some GTK sliders +to display the volume. plot will output data readable by gnuplot. + +Here is a sample plot script to plot output of the plot command that was +stored to plot.dat + +set xlabel "Seconds" +set ylabel "dB" +set yrange [-60:0] +plot 'plot.dat' using 1:2 title 'L RMS' with lines, \ + 'plot.dat' using 1:3 title 'L peak' with lines, \ + 'plot.dat' using 1:4 title 'L decay' with lines + +plot 'plot.dat' using 1:5 title 'R RMS' with lines, \ + 'plot.dat' using 1:6 title 'R peak' with lines, \ + 'plot.dat' using 1:7 title 'R decay' with lines + + diff --git a/tests/old/examples/level/demo.c b/tests/old/examples/level/demo.c new file mode 100644 index 0000000..502f50f --- /dev/null +++ b/tests/old/examples/level/demo.c @@ -0,0 +1,155 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * + * demo.c: sample application to display VU meter-like output of level + * Copyright (C) 2003 + * Thomas Vander Stichele + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +/* global array for the scale widgets, we'll assume stereo */ +GtkWidget *elapsed; +GtkWidget *scale[2][3]; + +static void +level_callback (GstElement * element, gdouble time, gint channel, + gdouble rms, gdouble peak, gdouble decay) +{ + gchar *label; + + label = g_strdup_printf ("%.3f", time); + gtk_label_set (GTK_LABEL (elapsed), label); + g_free (label); + gtk_range_set_value (GTK_RANGE (scale[channel][0]), rms); + gtk_range_set_value (GTK_RANGE (scale[channel][1]), peak); + gtk_range_set_value (GTK_RANGE (scale[channel][2]), decay); +} + +static gboolean +idler (gpointer data) +{ + GstElement *pipeline = GST_ELEMENT (data); + + g_print ("+"); + if (gst_bin_iterate (GST_BIN (pipeline))) + return TRUE; + gtk_main_quit (); + return FALSE; +} + +static void +setup_gui () +{ + GtkWidget *window; + GtkWidget *vbox; + GtkWidget *label, *hbox; + int c; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + g_signal_connect (window, "destroy", gtk_main_quit, NULL); + + vbox = gtk_vbox_new (TRUE, 0); + gtk_container_add (GTK_CONTAINER (window), vbox); + + /* elapsed widget */ + hbox = gtk_hbox_new (TRUE, 0); + label = gtk_label_new ("Elapsed"); + elapsed = gtk_label_new ("0.000"); + gtk_container_add (GTK_CONTAINER (hbox), label); + gtk_container_add (GTK_CONTAINER (hbox), elapsed); + gtk_container_add (GTK_CONTAINER (vbox), hbox); + + for (c = 0; c < 2; ++c) { + /* RMS */ + hbox = gtk_hbox_new (TRUE, 0); + label = gtk_label_new ("RMS"); + gtk_container_add (GTK_CONTAINER (hbox), label); + scale[c][0] = gtk_hscale_new_with_range (-90.0, 0.0, 0.2); + gtk_widget_set_size_request (scale[c][0], 100, -1); + gtk_container_add (GTK_CONTAINER (hbox), scale[c][0]); + gtk_container_add (GTK_CONTAINER (vbox), hbox); + /* peak */ + hbox = gtk_hbox_new (TRUE, 0); + label = gtk_label_new ("peak"); + gtk_container_add (GTK_CONTAINER (hbox), label); + scale[c][1] = gtk_hscale_new_with_range (-90.0, 0.0, 0.2); + gtk_widget_set_size_request (scale[c][1], 100, -1); + gtk_container_add (GTK_CONTAINER (hbox), scale[c][1]); + gtk_container_add (GTK_CONTAINER (vbox), hbox); + /* decay */ + hbox = gtk_hbox_new (TRUE, 0); + label = gtk_label_new ("decaying peek"); + gtk_container_add (GTK_CONTAINER (hbox), label); + scale[c][2] = gtk_hscale_new_with_range (-90.0, 0.0, 0.2); + gtk_widget_set_size_request (scale[c][2], 100, -1); + gtk_container_add (GTK_CONTAINER (hbox), scale[c][2]); + gtk_container_add (GTK_CONTAINER (vbox), hbox); + } + + gtk_widget_show_all (GTK_WIDGET (window)); +} + +int +main (int argc, char *argv[]) +{ + + GstElement *pipeline = NULL; + GError *error = NULL; + GstElement *level; + + gst_init (&argc, &argv); + gtk_init (&argc, &argv); + + pipeline = gst_parse_launchv ((const gchar **) &argv[1], &error); + if (error) { + g_print ("pipeline could not be constructed: %s\n", error->message); + g_print ("Please give a complete pipeline with a 'level' element.\n"); + g_print ("Example: sinesrc ! level ! %s\n", DEFAULT_AUDIOSINK); + g_error_free (error); + return 1; + } + + level = gst_bin_get_by_name (GST_BIN (pipeline), "level0"); + if (level == NULL) { + g_print ("Please give a pipeline with a 'level' element in it\n"); + return 1; + } + + g_object_set (level, "signal", TRUE, NULL); + g_signal_connect (level, "level", G_CALLBACK (level_callback), NULL); + + + /* setup GUI */ + setup_gui (); + + /* connect level signal */ + + /* go to main loop */ + gst_element_set_state (pipeline, GST_STATE_PLAYING); + g_idle_add (idler, pipeline); + + gtk_main (); + + return 0; +} diff --git a/tests/old/examples/level/plot.c b/tests/old/examples/level/plot.c new file mode 100644 index 0000000..6df0106 --- /dev/null +++ b/tests/old/examples/level/plot.c @@ -0,0 +1,123 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * + * plot.c: output data points to be graphed with gnuplot + * Copyright (C) 2003 + * Thomas Vander Stichele + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +gboolean got_channel[2] = { FALSE, FALSE }; /* to see if we got the signal for this one yet */ +gint channels = 0; /* guess at how many channels there are */ +gdouble last_time = 0.0; /* time of last signal */ +gdouble values[2][3]; /* array of levels from which to print */ + +static void +level_callback (GstElement * element, gdouble time, gint channel, + gdouble rms, gdouble peak, gdouble decay) +{ + int i = 0, j = 0; + gboolean got_all = FALSE; + + if (channel + 1 > channels) + channels = channel + 1; + + /* reset got_channel if this is a new time point */ + if (time > last_time) { + for (i = 0; i < channels; ++i) + got_channel[i] = FALSE; + last_time = time; + } + + /* store values */ + got_channel[channel] = TRUE; + values[channel][0] = rms; + values[channel][1] = peak; + values[channel][2] = decay; + + /* check if we have all channels, and output if we do */ + /* FIXME: this fails on the first, no ? */ + got_all = TRUE; + for (i = 0; i < channels; ++i) + if (!got_channel[i]) + got_all = FALSE; + if (got_all) { + g_print ("%f ", time); + for (i = 0; i < channels; ++i) + for (j = 0; j < 3; ++j) + g_print ("%f ", values[i][j]); + g_print ("\n"); + } +} + +static gboolean +idler (gpointer data) +{ + GstElement *pipeline = GST_ELEMENT (data); + + if (gst_bin_iterate (GST_BIN (pipeline))) + return TRUE; + + gtk_main_quit (); + return FALSE; +} + +int +main (int argc, char *argv[]) +{ + + GstElement *pipeline = NULL; + GError *error = NULL; + GstElement *level; + + gst_init (&argc, &argv); + gtk_init (&argc, &argv); + + pipeline = gst_parse_launchv ((const gchar **) &argv[1], &error); + if (error) { + g_print ("pipeline could not be constructed: %s\n", error->message); + g_print ("Please give a complete pipeline with a 'level' element.\n"); + g_print ("Example: sinesrc ! level ! %s\n", DEFAULT_AUDIOSINK); + g_error_free (error); + return 1; + } + + level = gst_bin_get_by_name (GST_BIN (pipeline), "level0"); + if (level == NULL) { + g_print ("Please give a pipeline with a 'level' element in it\n"); + return 1; + } + + g_object_set (level, "signal", TRUE, NULL); + g_signal_connect (level, "level", G_CALLBACK (level_callback), NULL); + + + /* go to main loop */ + gst_element_set_state (pipeline, GST_STATE_PLAYING); + g_idle_add (idler, pipeline); + + gtk_main (); + + return 0; +} -- 2.7.4