From 185612aae3b8acae2b32e0e6561691a7c640cd0d Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Sat, 22 Dec 2001 23:27:31 +0000 Subject: [PATCH] Initial revision Original commit message from CVS: Initial revision --- gst/cutter/Makefile.am | 9 + gst/cutter/README | 38 +++ gst/cutter/filter.func | 16 ++ gst/cutter/gstcutter.c | 419 +++++++++++++++++++++++++++++ gst/cutter/gstcutter.h | 84 ++++++ gst/flx/Makefile.am | 9 + gst/flx/flx_color.c | 94 +++++++ gst/flx/flx_color.h | 43 +++ gst/flx/flx_fmt.h | 136 ++++++++++ gst/flx/gstflxdec.c | 644 +++++++++++++++++++++++++++++++++++++++++++++ gst/flx/gstflxdec.h | 79 ++++++ gst/law/Makefile.am | 12 + gst/law/alaw-conversion.c | 195 ++++++++++++++ gst/law/alaw-conversion.h | 12 + gst/law/alaw-decode.c | 186 +++++++++++++ gst/law/alaw-decode.h | 69 +++++ gst/law/alaw-encode.c | 182 +++++++++++++ gst/law/alaw-encode.h | 69 +++++ gst/law/alaw.c | 95 +++++++ gst/law/mulaw-conversion.c | 102 +++++++ gst/law/mulaw-conversion.h | 10 + gst/law/mulaw-decode.c | 181 +++++++++++++ gst/law/mulaw-decode.h | 69 +++++ gst/law/mulaw-encode.c | 181 +++++++++++++ gst/law/mulaw-encode.h | 69 +++++ gst/law/mulaw.c | 103 ++++++++ gst/level/Makefile.am | 10 + gst/level/README | 11 + gst/level/filter.func | 45 ++++ gst/level/gstlevel.c | 285 ++++++++++++++++++++ gst/level/gstlevel.h | 69 +++++ gst/median/.gitignore | 7 + gst/median/Makefile.am | 9 + gst/median/gstmedian.c | 412 +++++++++++++++++++++++++++++ gst/median/gstmedian.h | 72 +++++ gst/spectrum/.gitignore | 7 + gst/spectrum/Makefile.am | 10 + gst/spectrum/README | 5 + gst/spectrum/gstspectrum.c | 242 +++++++++++++++++ gst/spectrum/gstspectrum.h | 67 +++++ gst/udp/.gitignore | 7 + gst/udp/Makefile.am | 10 + gst/udp/README | 28 ++ gst/udp/gstudp.c | 52 ++++ gst/udp/gstudpsink.c | 301 +++++++++++++++++++++ gst/udp/gstudpsink.h | 91 +++++++ gst/udp/gstudpsrc.c | 300 +++++++++++++++++++++ gst/udp/gstudpsrc.h | 88 +++++++ gst/wavparse/.gitignore | 7 + gst/wavparse/Makefile.am | 8 + gst/wavparse/gstriff.c | 144 ++++++++++ gst/wavparse/gstriff.h | 67 +++++ gst/wavparse/gstwavparse.c | 367 ++++++++++++++++++++++++++ gst/wavparse/gstwavparse.h | 99 +++++++ 54 files changed, 5926 insertions(+) create mode 100644 gst/cutter/Makefile.am create mode 100644 gst/cutter/README create mode 100644 gst/cutter/filter.func create mode 100644 gst/cutter/gstcutter.c create mode 100644 gst/cutter/gstcutter.h create mode 100644 gst/flx/Makefile.am create mode 100644 gst/flx/flx_color.c create mode 100644 gst/flx/flx_color.h create mode 100644 gst/flx/flx_fmt.h create mode 100644 gst/flx/gstflxdec.c create mode 100644 gst/flx/gstflxdec.h create mode 100644 gst/law/Makefile.am create mode 100644 gst/law/alaw-conversion.c create mode 100644 gst/law/alaw-conversion.h create mode 100644 gst/law/alaw-decode.c create mode 100644 gst/law/alaw-decode.h create mode 100644 gst/law/alaw-encode.c create mode 100644 gst/law/alaw-encode.h create mode 100644 gst/law/alaw.c create mode 100644 gst/law/mulaw-conversion.c create mode 100644 gst/law/mulaw-conversion.h create mode 100644 gst/law/mulaw-decode.c create mode 100644 gst/law/mulaw-decode.h create mode 100644 gst/law/mulaw-encode.c create mode 100644 gst/law/mulaw-encode.h create mode 100644 gst/law/mulaw.c create mode 100644 gst/level/Makefile.am create mode 100644 gst/level/README create mode 100644 gst/level/filter.func create mode 100644 gst/level/gstlevel.c create mode 100644 gst/level/gstlevel.h create mode 100644 gst/median/.gitignore create mode 100644 gst/median/Makefile.am create mode 100644 gst/median/gstmedian.c create mode 100644 gst/median/gstmedian.h create mode 100644 gst/spectrum/.gitignore create mode 100644 gst/spectrum/Makefile.am create mode 100644 gst/spectrum/README create mode 100644 gst/spectrum/gstspectrum.c create mode 100644 gst/spectrum/gstspectrum.h create mode 100644 gst/udp/.gitignore create mode 100644 gst/udp/Makefile.am create mode 100644 gst/udp/README create mode 100644 gst/udp/gstudp.c create mode 100644 gst/udp/gstudpsink.c create mode 100644 gst/udp/gstudpsink.h create mode 100644 gst/udp/gstudpsrc.c create mode 100644 gst/udp/gstudpsrc.h create mode 100644 gst/wavparse/.gitignore create mode 100644 gst/wavparse/Makefile.am create mode 100644 gst/wavparse/gstriff.c create mode 100644 gst/wavparse/gstriff.h create mode 100644 gst/wavparse/gstwavparse.c create mode 100644 gst/wavparse/gstwavparse.h diff --git a/gst/cutter/Makefile.am b/gst/cutter/Makefile.am new file mode 100644 index 0000000..d31d6f1 --- /dev/null +++ b/gst/cutter/Makefile.am @@ -0,0 +1,9 @@ +filterdir = $(libdir)/gst + +filter_LTLIBRARIES = libgstcutter.la + +libgstcutter_la_SOURCES = gstcutter.c + +noinst_HEADERS = gstcutter.h filter.func + +EXTRA_DIST = README diff --git a/gst/cutter/README b/gst/cutter/README new file mode 100644 index 0000000..fc0975e --- /dev/null +++ b/gst/cutter/README @@ -0,0 +1,38 @@ +cutter plugin by thomas + +SYNOPSIS + +This plugin emits signals when RMS level of audio signal crosses a +threshold for a given amount of time. + +As soon as the buffer's RMS is greater than the threshold value, the plugin fires a CUT_START signal. + +When the buffer's RMS level drops below the threshold value for a consecutive run length longer than the given runlength, it sends a CUT_STOP signal. + +When a pre-recording buffer is used, the plugin will delay throughput of data when it's in "silent" mode for a maximum length equal to the pre-recording buffer length. As soon as the input level crosses the threshold level, this pre-recorded buffer is flushed to the src pad (so you can actually record the audio just before the threshold crossing) after sending the signal. + +ARGUMENTS + +GstCutter::threshold + level (between 0 and 1) of threshold +GstCutter::threshold_dB + level of threshold in dB (between -inf and 0) +GstCutter::runlength + minimum length (in seconds) before plugin sends cut_stop signal +GstCutter::prelength + length of pre-recording buffer + +SIGNALS + + CUT_START + gets sent when the level of the signal goes above threshold level + CUT_STOP + gets sent when the level of the signal has been below the + threshold level for a number of consecutive iterations of which + the cumulative length is more than the runlength + +LIMITATIONS + + * RMS value is calculated over the whole data buffer, so + the time resolution is limited to the buffer length + * RMS value is calculated over all of the channels combined diff --git a/gst/cutter/filter.func b/gst/cutter/filter.func new file mode 100644 index 0000000..bdbe566 --- /dev/null +++ b/gst/cutter/filter.func @@ -0,0 +1,16 @@ +{ + guint j; + register double squaresum = 0.0; + + /* + * process data here + * input sample data enters in *in_data as 8 or 16 bit data + * samples for left and right channel are interleaved + */ + + for (j = 0; j < num_samples; j++) + squaresum += data[j] * data[j]; + + return (squaresum / (float) num_samples); +} + diff --git a/gst/cutter/gstcutter.c b/gst/cutter/gstcutter.c new file mode 100644 index 0000000..8161d50 --- /dev/null +++ b/gst/cutter/gstcutter.c @@ -0,0 +1,419 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + +#include +#include +#include "cutter.h" +#include "math.h" + + +static GstElementDetails cutter_details = { + "Cutter", + "Filter/Effect", + "Audio Cutter to split audio into non-silent bits", + VERSION, + "Thomas ", + "(C) 2001", +}; + + +/* Filter signals and args */ +enum { + /* FILL ME */ + CUT_START, + CUT_STOP, + LAST_SIGNAL +}; + +enum { + ARG_0, + ARG_THRESHOLD, + ARG_THRESHOLD_DB, + ARG_RUN_LENGTH, + ARG_PRE_LENGTH +}; + +GST_PADTEMPLATE_FACTORY (cutter_src_factory, + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "test_src", + "audio/raw", + "channels", GST_PROPS_INT_RANGE (1, 2) + ) +); + +GST_PADTEMPLATE_FACTORY (cutter_sink_factory, + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "test_src", + "audio/raw", + "channels", GST_PROPS_INT_RANGE (1, 2) + ) +); + +static void gst_cutter_class_init (GstCutterClass *klass); +static void gst_cutter_init (GstCutter *filter); + +static void gst_cutter_set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec); +static void gst_cutter_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec); + +static void gst_cutter_chain (GstPad *pad, GstBuffer *buf); +static double inline gst_cutter_16bit_ms (gint16* data, guint numsamples); +static double inline gst_cutter_8bit_ms (gint8* data, guint numsamples); + +void gst_cutter_get_caps (GstPad *pad, GstCutter* filter); + +static GstElementClass *parent_class = NULL; +static guint gst_cutter_signals[LAST_SIGNAL] = { 0 }; + +static GstPadNegotiateReturn +cutter_negotiate_src (GstPad *pad, GstCaps **caps, gpointer *data) +{ + GstCutter* filter = GST_CUTTER (gst_pad_get_parent (pad)); + + if (*caps==NULL) + return GST_PAD_NEGOTIATE_FAIL; + + return gst_pad_negotiate_proxy(pad,filter->sinkpad,caps); +} + +static GstPadNegotiateReturn +cutter_negotiate_sink (GstPad *pad, GstCaps **caps, gpointer *data) +{ + GstCutter* filter = GST_CUTTER (gst_pad_get_parent (pad)); + + if (*caps==NULL) + return GST_PAD_NEGOTIATE_FAIL; + + return gst_pad_negotiate_proxy(pad,filter->srcpad,caps); +} + +GType +gst_cutter_get_type(void) { + static GType cutter_type = 0; + + if (!cutter_type) { + static const GTypeInfo cutter_info = { + sizeof(GstCutterClass), NULL, NULL, (GClassInitFunc)gst_cutter_class_init, + NULL, + NULL, + sizeof(GstCutter), + 0, + (GInstanceInitFunc)gst_cutter_init, + }; + cutter_type = g_type_register_static(GST_TYPE_ELEMENT, "GstCutter", &cutter_info, 0); + } + return cutter_type; +} + +static void +gst_cutter_class_init (GstCutterClass *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_THRESHOLD, + g_param_spec_double ("threshold", "threshold", "threshold", + G_MINDOUBLE, G_MAXDOUBLE, 0, G_PARAM_READWRITE)); // CHECKME + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_THRESHOLD_DB, + g_param_spec_double ("threshold_dB", "threshold_dB", "threshold_dB", + G_MINDOUBLE, G_MAXDOUBLE, 0, G_PARAM_READWRITE)); // CHECKME + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_RUN_LENGTH, + g_param_spec_double ("runlength", "runlength", "runlength", + G_MINDOUBLE, G_MAXDOUBLE, 0, G_PARAM_READWRITE)); // CHECKME + + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PRE_LENGTH, + g_param_spec_double ("prelength", "prelength", "prelength", + G_MINDOUBLE, G_MAXDOUBLE, 0, G_PARAM_READWRITE)); // CHECKME + gst_cutter_signals[CUT_START] = + g_signal_new ("cut_start", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GstCutterClass, cut_start), NULL, NULL, + g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + gst_cutter_signals[CUT_STOP] = + g_signal_new ("cut_stop", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GstCutterClass, cut_stop), NULL, NULL, + g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + + + gobject_class->set_property = gst_cutter_set_property; + gobject_class->get_property = gst_cutter_get_property; +} + +static void +gst_cutter_init (GstCutter *filter) +{ + filter->sinkpad = gst_pad_new_from_template (cutter_sink_factory (),"sink"); + filter->srcpad = gst_pad_new_from_template (cutter_src_factory (),"src"); + + filter->threshold_level = 0.1; + filter->threshold_length = 0.5; + filter->silent_run_length = 0.0; + filter->silent = TRUE; + + filter->pre_length = 0.2; + filter->pre_run_length = 0.0; + filter->pre_buffer = NULL; + + gst_pad_set_negotiate_function (filter->sinkpad,cutter_negotiate_sink); + gst_pad_set_negotiate_function (filter->srcpad,cutter_negotiate_src); + + gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad); + gst_pad_set_chain_function (filter->sinkpad, gst_cutter_chain); + filter->srcpad = gst_pad_new ("src", GST_PAD_SRC); + gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad); +} + +static void +gst_cutter_chain (GstPad *pad, GstBuffer *buf) +{ + GstCutter *filter; + gint16 *in_data; + double RMS = 0.0; /* RMS of signal in buffer */ + double ms = 0.0; /* mean square value of buffer */ + static gboolean silent_prev = FALSE; /* previous value of silent */ + GstBuffer* prebuf; /* pointer to a prebuffer element */ + + g_return_if_fail (pad != NULL); + g_return_if_fail (GST_IS_PAD (pad)); + g_return_if_fail (buf != NULL); + + filter = GST_CUTTER (GST_OBJECT_PARENT (pad)); + g_return_if_fail (filter != NULL); + g_return_if_fail (GST_IS_CUTTER (filter)); + + g_return_if_fail (gst_audio_is_buffer_framed (pad, buf) == TRUE); + + if (!filter->have_caps) gst_cutter_get_caps (pad, filter); + + in_data = (gint16 *) GST_BUFFER_DATA (buf); + g_print ("DEBUG: cutter: length of prerec buffer: %.3f sec\n", + filter->pre_run_length); + + /* calculate mean square value on buffer */ + switch (filter->width) + { + case 16: + ms = gst_cutter_16bit_ms (in_data, GST_BUFFER_SIZE (buf) / 2); + break; + case 8: + ms = gst_cutter_8bit_ms ((gint8 *) in_data, GST_BUFFER_SIZE (buf)); + break; + default: + /* this shouldn't happen */ + g_print ("WARNING: no mean square function for width %d\n", + filter->width); + break; + } + + silent_prev = filter->silent; + + RMS = sqrt (ms) / (double) filter->max_sample; + /* if RMS below threshold, add buffer length to silent run length count + * if not, reset + */ + //g_print ("DEBUG: cutter: ms %f, RMS %f\n", ms, RMS); + if (RMS < filter->threshold_level) + filter->silent_run_length += gst_audio_length (filter->srcpad, buf); + else + { + filter->silent_run_length = 0.0; + filter->silent = FALSE; + } + + if (filter->silent_run_length > filter->threshold_length) + /* it has been silent long enough, flag it */ + filter->silent = TRUE; + + /* has the silent status changed ? if so, send right signal + * and, if from silent -> not silent, flush pre_record buffer + */ + if (filter->silent != silent_prev) + { + if (filter->silent) + { +// g_print ("DEBUG: cutter: cut to here, turning off out\n"); + gtk_signal_emit (G_OBJECT (filter), gst_cutter_signals[CUT_STOP]); + } + else + { +// g_print ("DEBUG: cutter: start from here, turning on out\n"); + /* first of all, flush current buffer */ + gtk_signal_emit (G_OBJECT (filter), gst_cutter_signals[CUT_START]); + g_print ("DEBUG: cutter: flushing buffer "); + while (filter->pre_buffer) + { + g_print ("."); + prebuf = (g_list_first (filter->pre_buffer))->data; + filter->pre_buffer = g_list_remove (filter->pre_buffer, prebuf); + gst_pad_push (filter->srcpad, prebuf); + filter->pre_run_length = 0.0; + } + g_print ("\n"); + } + } + /* now check if we have to add the new buffer to the cache or to the pad */ + if (filter->silent) + { + filter->pre_buffer = g_list_append (filter->pre_buffer, buf); + filter->pre_run_length += gst_audio_length (filter->srcpad, buf); + while (filter->pre_run_length > filter->pre_length) + { + prebuf = (g_list_first (filter->pre_buffer))->data; + filter->pre_buffer = g_list_remove (filter->pre_buffer, prebuf); + gst_pad_push (filter->srcpad, prebuf); + filter->pre_run_length -= gst_audio_length (filter->srcpad, prebuf); + } + } + else + gst_pad_push (filter->srcpad, buf); +} + +static double inline +gst_cutter_16bit_ms (gint16* data, guint num_samples) +#include "filter.func" + +static double inline +gst_cutter_8bit_ms (gint8* data, guint num_samples) +#include "filter.func" + +static void +gst_cutter_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstCutter *filter; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_CUTTER (object)); + filter = GST_CUTTER (object); + + switch (prop_id) + { + case ARG_THRESHOLD: + /* set the level */ + filter->threshold_level = g_value_get_double (value); + g_print ("DEBUG: cutter: set threshold level to %f\n", + filter->threshold_level); + break; + case ARG_THRESHOLD_DB: + /* set the level given in dB + * value in dB = 20 * log (value) + * values in dB < 0 result in values between 0 and 1 + */ + filter->threshold_level = pow (10, g_value_get_double (value) / 20); + g_print ("DEBUG: cutter: set threshold level to %f\n", + filter->threshold_level); + break; + case ARG_RUN_LENGTH: + /* set the minimum length of the silent run required */ + filter->threshold_length = g_value_get_double (value); + break; + case ARG_PRE_LENGTH: + /* set the length of the pre-record block */ + filter->pre_length = g_value_get_double (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_cutter_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstCutter *filter; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail (GST_IS_CUTTER(object)); + filter = GST_CUTTER (object); + + switch (prop_id) + { + case ARG_RUN_LENGTH: + g_value_set_double (value, filter->threshold_length); + break; + case ARG_THRESHOLD: + g_value_set_double (value, filter->threshold_level); + break; + case ARG_THRESHOLD_DB: + g_value_set_double (value, 20 * log (filter->threshold_level)); + break; + case ARG_PRE_LENGTH: + g_value_set_double (value, filter->pre_length); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +plugin_init (GModule *module, GstPlugin *plugin) +{ + GstElementFactory *factory; + + factory = gst_elementfactory_new("cutter",GST_TYPE_CUTTER, + &cutter_details); + g_return_val_if_fail(factory != NULL, FALSE); + + gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (cutter_src_factory)); + gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (cutter_sink_factory)); + + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); + + /* load audio support library */ + if (!gst_library_load ("gstaudio")) + { + gst_info ("cutter: could not load support library: 'gstaudio'\n"); + return FALSE; + } + + return TRUE; +} + +GstPluginDesc plugin_desc = +{ + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "cutter", + plugin_init +}; + +void +gst_cutter_get_caps (GstPad *pad, GstCutter* filter) +{ + GstCaps *caps = NULL; + + caps = GST_PAD_CAPS (pad); + // FIXME : Please change this to a better warning method ! + if (caps == NULL) + printf ("WARNING: cutter: get_caps: Could not get caps of pad !\n"); + filter->width = gst_caps_get_int (caps, "width"); + filter->max_sample = gst_audio_highest_sample_value (pad); + filter->have_caps = TRUE; +} diff --git a/gst/cutter/gstcutter.h b/gst/cutter/gstcutter.h new file mode 100644 index 0000000..18de878 --- /dev/null +++ b/gst/cutter/gstcutter.h @@ -0,0 +1,84 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + + +#ifndef __GST_CUTTER_H__ +#define __GST_CUTTER_H__ + + +#include +#include +// #include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GST_TYPE_CUTTER \ + (gst_cutter_get_type()) +#define GST_CUTTER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CUTTER,GstCutter)) +#define GST_CUTTER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ULAW,GstCutter)) +#define GST_IS_CUTTER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CUTTER)) +#define GST_IS_CUTTER_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CUTTER)) + +typedef struct _GstCutter GstCutter; +typedef struct _GstCutterClass GstCutterClass; + +struct _GstCutter +{ + GstElement element; + + GstPad *sinkpad, *srcpad; + + double threshold_level; /* level below which to cut */ + double threshold_length; /* how long signal has to remain + * below this level before cutting + */ + double silent_run_length; /* how long has it been below threshold ? */ + gboolean silent; + + double pre_length; /* how long can the pre-record buffer be ? */ + double pre_run_length; /* how long is it currently ? */ + GList *pre_buffer; + + gboolean have_caps; /* did we get the needed caps yet ? */ + gint width; /* bit width of data */ + long max_sample; /* maximum sample value */ +}; + +struct _GstCutterClass { + GstElementClass parent_class; + void (*cut_start) (GstCutter* filter); + void (*cut_stop) (GstCutter* filter); +}; + +GType gst_cutter_get_type(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_STEREO_H__ */ diff --git a/gst/flx/Makefile.am b/gst/flx/Makefile.am new file mode 100644 index 0000000..79a6fba --- /dev/null +++ b/gst/flx/Makefile.am @@ -0,0 +1,9 @@ +filterdir = $(libdir)/gst + +filter_LTLIBRARIES = libgstflxdec.la + +libgstflxdec_la_SOURCES = gstflxdec.c flx_color.c +libgstflxdec_la_CFLAGS = $(GST_CFLAGS) + +noinst_HEADERS = flx_fmt.h flx_color.h gstflxdec.h + diff --git a/gst/flx/flx_color.c b/gst/flx/flx_color.c new file mode 100644 index 0000000..c61052d --- /dev/null +++ b/gst/flx/flx_color.c @@ -0,0 +1,94 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + +#include +#include + + +#include "flx_color.h" + +FlxColorSpaceConverter * +flx_colorspace_converter_new(gint width, gint height) +{ + FlxColorSpaceConverter *new = g_malloc(sizeof(FlxColorSpaceConverter)); + + new->width = width; + new->height = height; + + memset(new->palvec, 0, sizeof(new->palvec)); + return new; +} + +void +flx_colorspace_converter_destroy(FlxColorSpaceConverter *flxpal) +{ + g_return_if_fail(flxpal != NULL); + + g_free(flxpal); +} + +void +flx_colorspace_convert(FlxColorSpaceConverter *flxpal, guchar *src, guchar *dest) +{ + guint size, col; + + g_return_if_fail(flxpal != NULL); + g_return_if_fail(src != dest); + + + size = flxpal->width * flxpal->height; + + while(size--) { + col = (*src++ * 3); + *dest++ = flxpal->palvec[col+2]; + *dest++ = flxpal->palvec[col+1]; + *dest++ = flxpal->palvec[col]; + *dest++ = 0; + } + +} + + +void +flx_set_palette_vector(FlxColorSpaceConverter *flxpal, guint start, guint num, guchar *newpal) +{ + guint grab; + + g_return_if_fail(flxpal != NULL); + g_return_if_fail(start < 0x100); + + grab = ((start + num) > 0x100 ? 0x100 - start : num); + + memcpy(&flxpal->palvec[start * 3], newpal, grab*3); + +} + +void +flx_set_color(FlxColorSpaceConverter *flxpal, guint colr, guint red, guint green, guint blue) +{ + + g_return_if_fail(flxpal != NULL); + g_return_if_fail(colr < 0x100); + + flxpal->palvec[(colr * 3)] = red; + flxpal->palvec[(colr * 3) + 1] = green; + flxpal->palvec[(colr * 3) + 2] = blue; +} + + diff --git a/gst/flx/flx_color.h b/gst/flx/flx_color.h new file mode 100644 index 0000000..5676c87 --- /dev/null +++ b/gst/flx/flx_color.h @@ -0,0 +1,43 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + +typedef enum { + FLX_COLORSPACE_RGB8, + FLX_COLORSPACE_RGB32, +} FlxColorSpaceType; + + +typedef struct _FlxColorSpaceConverter FlxColorSpaceConverter; + +struct _FlxColorSpaceConverter { + guint width; + guint height; + guchar palvec[768]; +}; + + +void flx_colorspace_converter_destroy(FlxColorSpaceConverter *flxpal); +void flx_colorspace_convert(FlxColorSpaceConverter *flxpal, guchar *src, guchar *dest); +FlxColorSpaceConverter * flx_colorspace_converter_new(gint width, gint height); + +void flx_set_palette_vector(FlxColorSpaceConverter *flxpal, guint start, guint num, + guchar *newpal); +void flx_set_color(FlxColorSpaceConverter *flxpal, guint colr, guint red, guint green, + guint blue); + diff --git a/gst/flx/flx_fmt.h b/gst/flx/flx_fmt.h new file mode 100644 index 0000000..5323de6 --- /dev/null +++ b/gst/flx/flx_fmt.h @@ -0,0 +1,136 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + + +#ifndef __GST_FLX_FMT__H__ +#define __GST_FLX_FMT_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +enum Flx_TypeChunk +{ + /* frame chunks */ + FLX_PREFIX_TYPE = 0xf100, + FLX_SCRIPT_CHUNK = 0xf1e0, + FLX_FRAME_TYPE = 0xf1fa, + FLX_SEGMENT_TABLE = 0xf1fb, + FLX_HUFFMAN_TABLE = 0xf1fc, + + /* sub chunks */ + FLX_CEL_DATA = 3, + FLX_COLOR256 = 4, + FLX_SS2 = 7, + FLX_COLOR64 = 11, + FLX_LC = 12, + FLX_BLACK = 13, + FLX_BRUN = 15, + FLX_COPY = 16, + FLX_MINI = 18, + FLX_DTA_RUN = 25, + FLX_DTA_COPY = 26, + FLX_DTA_LC = 27, + FLX_LABEL = 31, + FLX_BMP_MASK = 32, + FLX_MLEV_MASK = 33, + FLX_SEGMENT = 34, + FLX_KEY_IMAGE = 35, + FLX_KEY_PAL = 36, + FLX_REGION = 37, + FLX_WAVE = 38, + FLX_USERSTRING = 39, + FLX_RGN_MASK = 40, + +}; + +enum Flx_MagicHdr +{ + FLX_MAGICHDR_FLI = 0xaf11, + FLX_MAGICHDR_FLC = 0xaf12, + FLX_MAGICHDR_FLX = 0xaf44, + FLX_MAGICHDR_HUFFBWT = 0xaf30, +}; + + + +typedef struct _FlxHeader +{ + guint32 size; + guint16 type; + guint16 frames; + guint16 width,height,depth,flags; + guint32 speed; + guint16 reserved1; + /* FLC */ + guint32 created,creator,updated,updater; + guint16 aspect_dx, aspect_dy; + /* EGI */ + guint16 ext_flags,keyframes,totalframes; + guint32 req_memory; + guint16 max_regions,transp_num; + guchar reserved2[24]; + /* FLC */ + guint32 oframe1,oframe2; + guchar reserved3[40]; +} FlxHeader; +#define FlxHeaderSize 128 + +typedef struct _FlxFrameChunk +{ + guint32 size; + guint16 id; +} FlxFrameChunk; +#define FlxFrameChunkSize 6 + +typedef struct _FlxPrefixChunk +{ + guint16 chunks; + guchar reserved[8]; +} FlxPrefixChunk; + +typedef struct _FlxSegmentTable +{ + guint16 segments; +} FlxSegmentTable; + +typedef struct _FlxHuffmanTable +{ + guint16 codelength; + guint16 numcodes; + guchar reserved[6]; +} FlxHuffmanTable; + +typedef struct _FlxFrameType +{ + guint16 chunks; + guint16 delay; + guchar reserved[6]; +} FlxFrameType; +#define FlxFrameTypeSize 10 + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_FLX_FMT_H__ */ diff --git a/gst/flx/gstflxdec.c b/gst/flx/gstflxdec.c new file mode 100644 index 0000000..d6052bb --- /dev/null +++ b/gst/flx/gstflxdec.c @@ -0,0 +1,644 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + +#include + +#include "flx_fmt.h" +#include "gstflxdec.h" + +static GstCaps* flxdec_typefind(GstBuffer *buf, gpointer private); + +/* flx element information */ +static GstElementDetails flxdec_details = { + "FLX Decoder", + "flxdec", + "FLX decoder", + VERSION, + "Sepp Wijnands " + "(C) 2001", +}; + +static GstTypeDefinition flxdec_definition = { + "flxdec_video/fli", + "video/fli", + ".flc .fli", + flxdec_typefind, +}; + +/* Flx signals and args */ +enum { + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0 +}; + +/* input */ +GST_PADTEMPLATE_FACTORY (sink_factory, + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "flxdec_sink", + "video/fli", + NULL + ) +) + +/* output */ +GST_PADTEMPLATE_FACTORY (src_video_factory, + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "src_video", + "video/raw", + "format", GST_PROPS_FOURCC (GST_MAKE_FOURCC ('R', 'G', 'B', ' ')), + "bpp", GST_PROPS_INT (32), + "depth", GST_PROPS_INT (32), + "endianness", GST_PROPS_INT (G_LITTLE_ENDIAN), + "red_mask", GST_PROPS_INT (0x00ff0000), + "green_mask", GST_PROPS_INT (0x0000ff00), + "blue_mask", GST_PROPS_INT (0x000000ff), + "width", GST_PROPS_INT_RANGE(320, 1280), + "height", GST_PROPS_INT_RANGE(200, 1024) + ) +) + + +static void gst_flxdec_class_init (GstFlxDecClass *klass); +static void gst_flxdec_init (GstFlxDec *flxdec); + +static void gst_flxdec_loop (GstElement *element); + +static void gst_flxdec_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void gst_flxdec_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); + + +static void flx_decode_color(GstFlxDec *, guchar *, guchar *); +static void flx_decode_brun(GstFlxDec *, guchar *, guchar *); +static void flx_decode_delta_fli(GstFlxDec *, guchar *, guchar *); +static void flx_decode_delta_flc(GstFlxDec *, guchar *, guchar *); + +#define rndalign(off) ((off) + ((off) % 2)) + +static GstElementClass *parent_class = NULL; + +static GstCaps* +flxdec_typefind (GstBuffer *buf, gpointer private) +{ + guchar *data = GST_BUFFER_DATA(buf); + GstCaps *new; + + // check magic + if ((data[4] == 0x11 || data[4] == 0x12 + || data[4] == 0x30 || data[4] == 0x44) && data[5] == 0xaf) { + // check the frame type of the first frame + if ((data[132] == 0x00 || data[132] == 0xfa) && data[133] == 0xf1) { + g_print("GstFlxDec: found supported flx format\n"); + new = gst_caps_new("flxdec_typefind","video/fli", NULL); + return new; + } + } + + return NULL; +} + + +GType +gst_flxdec_get_type(void) +{ + static GType flxdec_type = 0; + + if (!flxdec_type) { + static const GTypeInfo flxdec_info = { + sizeof(GstFlxDecClass), NULL, + NULL, + (GClassInitFunc)gst_flxdec_class_init, + NULL, + NULL, + sizeof(GstFlxDec), + 0, + (GInstanceInitFunc)gst_flxdec_init, + }; + flxdec_type = g_type_register_static(GST_TYPE_ELEMENT, "GstFlxDec", &flxdec_info, 0); + } + return flxdec_type; +} + +static void +gst_flxdec_class_init (GstFlxDecClass *klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass*)klass; + gstelement_class = (GstElementClass*)klass; + + parent_class = g_type_class_ref(GST_TYPE_ELEMENT); + + gobject_class->set_property = NULL; + gobject_class->get_property = NULL; + +} + + + +static void +gst_flxdec_init(GstFlxDec *flxdec) +{ + flxdec->sinkpad = gst_pad_new_from_template ( + GST_PADTEMPLATE_GET (sink_factory), "sink"); + gst_element_add_pad(GST_ELEMENT(flxdec),flxdec->sinkpad); + gst_element_set_loop_function(GST_ELEMENT(flxdec),gst_flxdec_loop); + + flxdec->srcpad = gst_pad_new_from_template ( + GST_PADTEMPLATE_GET (src_video_factory), "src"); + gst_element_add_pad(GST_ELEMENT(flxdec),flxdec->srcpad); + + flxdec->buf = NULL; + flxdec->offset = 0; + flxdec->new_buf = TRUE; + +} + +static void +flx_decode_chunks (GstFlxDec *flxdec , gulong count, gchar *data, gchar *dest) +{ + FlxFrameChunk *hdr; + + g_return_if_fail(data != NULL); + + while (count--) { + hdr = (FlxFrameChunk *) data; + data += FlxFrameChunkSize; + + switch(hdr->id) + { + case FLX_COLOR64: + case FLX_COLOR256: + flx_decode_color(flxdec, data, dest); + data += rndalign(hdr->size) - FlxFrameChunkSize; + break; + + case FLX_BRUN: + flx_decode_brun(flxdec, data, dest); + data += rndalign(hdr->size) - FlxFrameChunkSize; + break; + + case FLX_LC: + flx_decode_delta_fli(flxdec, data, dest); + data += rndalign(hdr->size) - FlxFrameChunkSize; + break; + + case FLX_SS2: + flx_decode_delta_flc(flxdec, data, dest); + data += rndalign(hdr->size) - FlxFrameChunkSize; + break; + + case FLX_BLACK: + memset(dest, 0, flxdec->size); + break; + + case FLX_MINI: + data += rndalign(hdr->size) - FlxFrameChunkSize; + break; + + default: + g_print("GstFlxDec: Unimplented chunk type: 0x%02x size: %d\n", + hdr->id, hdr->size); + g_print("GstFlxDec: Skipping...\n"); + data += rndalign(hdr->size) - FlxFrameChunkSize; + break; + } + } +} + + +static void +flx_decode_color(GstFlxDec *flxdec, guchar *data, guchar *dest) +{ + guint packs, count, indx; + + g_return_if_fail(flxdec != NULL); + + packs = (data[0] + (data[1] << 8)); + + data += 2; + indx = 0; + + g_print("GstFlxDec: cmap packs: %d\n", packs); + while (packs--) { + /* color map index + skip count */ + indx += *data++; + + /* number of rgb triplets */ + count = *data++ & 0xff; + if (count == 0) + count = 256; + + g_print("GstFlxDec: cmap count: %d (indx: %d)\n", count, indx); + flx_set_palette_vector(flxdec->converter, indx, count, data); + + data += (count * 3); + } +} + +static void +flx_decode_brun(GstFlxDec *flxdec, guchar *data, guchar *dest) +{ + gulong count, lines, row; + guchar x; + + g_return_if_fail(flxdec != NULL); + + lines = flxdec->hdr.height; + while(lines--) { + /* packet count. + * should not be used anymore, since the flc format can + * contain more then 255 RLE packets. we use the frame + * width instead. + */ + data++; + + row = flxdec->hdr.width; + while(row) { + count = *data++; + + if (count > 0x7f) { + /* literal run */ + count = 0x100 - count; + row -= count; + + while(count--) + *dest++ = *data++; + + } else { + /* replicate run */ + row -= count; + x = *data++; + + while(count--) + *dest++ = x; + } + } + } +} + +static void +flx_decode_delta_fli(GstFlxDec *flxdec, guchar *data, guchar *dest) +{ + gulong count, packets, lines, start_line, start_l; + guchar *start_p, x; + + g_return_if_fail(flxdec != NULL); + g_return_if_fail(flxdec->delta != NULL); + + + /* use last frame for delta */ + memcpy(dest, GST_BUFFER_DATA(flxdec->delta), + GST_BUFFER_SIZE(flxdec->delta)); + + start_line = (data[0] + (data[1] << 8)); + lines = (data[2] + (data[3] << 8)); + data += 4; + + /* start position of delta */ + dest += (flxdec->hdr.width * start_line); + start_p = dest; + start_l = lines; + + while(lines--) { + /* packet count */ + packets = *data++; + + dest = start_p + (flxdec->hdr.width * (start_l - lines)); + + while(packets--) { + /* skip count */ + dest += *data++; + + /* RLE count */ + count = *data++; + + if (count > 0x7f) { + /* literal run */ + count = 0x100 - count; + x = *data++; + + while (count--) + *dest++ = x; + + } else { + /* replicate run */ + while (count--) + *dest++ = *data++; + } + } + } +} + +static void +flx_decode_delta_flc(GstFlxDec *flxdec, guchar *data, guchar *dest) +{ + gulong count, lines, start_l, opcode; + guchar *start_p; + + g_return_if_fail(flxdec != NULL); + g_return_if_fail(flxdec->delta != NULL); + + + /* use last frame for delta */ + memcpy(dest, GST_BUFFER_DATA(flxdec->delta), + GST_BUFFER_SIZE(flxdec->delta)); + + lines = (data[0] + (data[1] << 8)); + data += 2; + + start_p = dest; + start_l = lines; + + while(lines--) { + dest = start_p + (flxdec->hdr.width * (start_l - lines)); + + /* process opcode(s) */ + while ((opcode = (data[0] + (data[1] << 8))) & 0xc000) { + data += 2; + if ((opcode & 0xc000) == 0xc000) { + /* skip count */ + start_l += (0x10000 - opcode); + dest += flxdec->hdr.width * (0x10000 - opcode); + } else { + /* last pixel */ + dest += flxdec->hdr.width; + *dest++ = (opcode & 0xff); + } + } + data += 2; + + /* last opcode is the packet count */ + while(opcode--) { + /* skip count */ + dest += *data++; + + /* RLE count */ + count = *data++; + + if (count > 0x7f) { + /* replicate word run */ + count = 0x100 - count; + while (count--) { + *dest++ = data[0]; + *dest++ = data[1]; + } + data += 2; + } else { + /* literal word run */ + while (count--) { + *dest++ = *data++; + *dest++ = *data++; + } + } + } + } +} + +static GstBuffer* +flx_get_data(GstFlxDec *flxdec, gulong size) +{ + GstBuffer *retbuf; + + g_return_val_if_fail (flxdec != NULL, NULL); + + if (flxdec->new_buf) { + retbuf = gst_pad_pullregion(flxdec->sinkpad, + GST_REGION_OFFSET_LEN, 0, size); + flxdec->new_buf = FALSE; + flxdec->offset = size; + } else { + retbuf = gst_pad_pullregion(flxdec->sinkpad, GST_REGION_OFFSET_LEN, + flxdec->offset, size); + flxdec->offset += size; + } + + return retbuf; +} + + +static void +gst_flxdec_loop (GstElement *element) +{ + GstBuffer *buf; + GstBuffer *databuf; + guchar *data, *chunk; + + GstFlxDec *flxdec; + FlxHeader *flxh; + FlxFrameChunk *flxfh; + + g_return_if_fail (element != NULL); + g_return_if_fail (GST_IS_FLXDEC(element)); + + GST_DEBUG (0, "entering loop function\n"); + + flxdec = GST_FLXDEC(element); + + databuf = flx_get_data(flxdec, FlxHeaderSize); + + g_return_if_fail (databuf != NULL); + + data = GST_BUFFER_DATA(databuf); + + memcpy((char *) &flxdec->hdr, data, sizeof(FlxHeader)); + + gst_buffer_unref (databuf); + + flxh = &flxdec->hdr; + + // check header + if (flxh->type != FLX_MAGICHDR_FLI && + flxh->type != FLX_MAGICHDR_FLC && + flxh->type != FLX_MAGICHDR_FLX) + return; + + + g_print("GstFlxDec: size : %d\n", flxh->size); + g_print("GstFlxDec: frames : %d\n", flxh->frames); + g_print("GstFlxDec: width : %d\n", flxh->width); + g_print("GstFlxDec: height : %d\n", flxh->height); + g_print("GstFlxDec: depth : %d\n", flxh->depth); + g_print("GstFlxDec: speed : %d\n", flxh->speed); + + gst_pad_set_caps (flxdec->srcpad, + gst_caps_new ( + "src_video", + "video/raw", + gst_props_new ( + "format", GST_PROPS_FOURCC (GST_MAKE_FOURCC ('R', 'G', 'B', ' ')), + "bpp", GST_PROPS_INT (32), + "depth", GST_PROPS_INT (32), + "endianness", GST_PROPS_INT (G_LITTLE_ENDIAN), + "red_mask", GST_PROPS_INT (0x00ff0000), + "green_mask", GST_PROPS_INT (0x0000ff00), + "blue_mask", GST_PROPS_INT (0x000000ff), + "width", GST_PROPS_INT (flxh->width), + "height", GST_PROPS_INT (flxh->height), + NULL))); + + if (flxh->depth <= 8) + flxdec->converter = flx_colorspace_converter_new(flxh->width, flxh->height); + + if (flxh->type == FLX_MAGICHDR_FLC || + flxh->type == FLX_MAGICHDR_FLX) { + g_print("GstFlxDec: (FLC) aspect_dx : %d\n", + flxh->aspect_dx); + g_print("GstFlxDec: (FLC) aspect_dy : %d\n", + flxh->aspect_dy); + g_print("GstFlxDec: (FLC) oframe1 : 0x%08x\n", + flxh->oframe1); + g_print("GstFlxDec: (FLC) oframe2 : 0x%08x\n", + flxh->oframe2); + } + + + flxdec->size = (flxh->width * flxh->height); + + // create delta and output frame + flxdec->frame = gst_buffer_new(); + flxdec->delta = gst_buffer_new(); + GST_BUFFER_DATA(flxdec->frame) = g_malloc(flxdec->size); + GST_BUFFER_SIZE(flxdec->frame) = flxdec->size; + GST_BUFFER_DATA(flxdec->delta) = g_malloc(flxdec->size); + GST_BUFFER_SIZE(flxdec->delta) = flxdec->size; + + do + { + + databuf = flx_get_data(flxdec, FlxFrameChunkSize); + + flxfh = (FlxFrameChunk *) GST_BUFFER_DATA(databuf); + + switch(flxfh->id) + { + case FLX_FRAME_TYPE: + buf = flx_get_data(flxdec, flxfh->size-FlxFrameChunkSize); + + chunk = GST_BUFFER_DATA(buf); + + if (((FlxFrameType *)chunk)->chunks == 0) + break; + + // create 32 bits output frame + flxdec->out = gst_buffer_new(); + GST_BUFFER_DATA(flxdec->out) = g_malloc(flxdec->size * 4); + GST_BUFFER_SIZE(flxdec->out) = flxdec->size * 4; + + + // decode chunks + flx_decode_chunks(flxdec, + ((FlxFrameType *)chunk)->chunks, + GST_BUFFER_DATA(buf) + FlxFrameTypeSize, + GST_BUFFER_DATA(flxdec->frame)); + + // destroy input buffer + gst_buffer_unref(buf); + + // save copy of the current frame for possible delta. + memcpy(GST_BUFFER_DATA(flxdec->delta), + GST_BUFFER_DATA(flxdec->frame), + GST_BUFFER_SIZE(flxdec->delta)); + + // convert current frame. + flx_colorspace_convert(flxdec->converter, + GST_BUFFER_DATA(flxdec->frame), + GST_BUFFER_DATA(flxdec->out)); + + //GST_BUFFER_FLAG_SET(flxdec->out, GST_BUFFER_FLUSH); + gst_pad_push(flxdec->srcpad, flxdec->out); + + break; + } + + // destroy header buffer + gst_buffer_unref(databuf); + + } + while (!GST_ELEMENT_IS_COTHREAD_STOPPING (element)); + +} + +static void +gst_flxdec_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstFlxDec *flxdec; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_FLXDEC(object)); + flxdec = GST_FLXDEC(object); + + switch (prop_id) { + default: + break; + } +} + +static void +gst_flxdec_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstFlxDec *flxdec; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_FLXDEC(object)); + flxdec = GST_FLXDEC(object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +plugin_init (GModule *module, GstPlugin *plugin) +{ + GstElementFactory *factory; + GstTypeFactory *type; + + factory = gst_elementfactory_new("flxdec", GST_TYPE_FLXDEC, &flxdec_details); + g_return_val_if_fail(factory != NULL, FALSE); + + gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (sink_factory)); + gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (src_video_factory)); + + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); + + type = gst_typefactory_new (&flxdec_definition); + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (type)); + + return TRUE; +} + +GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "flxdec", + plugin_init +}; diff --git a/gst/flx/gstflxdec.h b/gst/flx/gstflxdec.h new file mode 100644 index 0000000..cc4c94d --- /dev/null +++ b/gst/flx/gstflxdec.h @@ -0,0 +1,79 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + +#ifndef __GST_FLX_DECODER_H__ +#define __GST_FLX_DECODER_H__ + +#include + +#include "flx_color.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* Definition of structure storing data for this element. */ +typedef struct _GstFlxDec GstFlxDec; +struct _GstFlxDec { + GstElement element; + + GstPad *sinkpad,*srcpad; + + gboolean active, new_meta, new_buf; + + GstBuffer *buf, *out, *delta, *frame; + gulong offset, size; + + FlxColorSpaceConverter *converter; + + FlxHeader hdr; +}; + +/* Standard definition defining a class for this element. */ +typedef struct _GstFlxDecClass GstFlxDecClass; +struct _GstFlxDecClass { + GstElementClass parent_class; +}; + +/* Standard macros for defining types for this element. */ +#define GST_TYPE_FLXDEC \ + (gst_flxdec_get_type()) +#define GST_FLXDEC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FLXDEC,GstFlxDec)) +#define GST_FLXDEC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FLXDEC,GstFlxDec)) +#define GST_IS_FLXDEC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FLXDEC)) +#define GST_IS_FLXDEC_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FLXDEC)) + +#define FLXDEC_BUFSIZE(buf, offset) \ + ((GST_BUFFER_OFFSET(buf) + GST_BUFFER_SIZE(buf)) - offset) + +/* Standard function returning type information. */ +GType gst_flxdec_get_type(void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_FLX_DECODER_H__ */ diff --git a/gst/law/Makefile.am b/gst/law/Makefile.am new file mode 100644 index 0000000..76a73f7 --- /dev/null +++ b/gst/law/Makefile.am @@ -0,0 +1,12 @@ +filterdir = $(libdir)/gst + +filter_LTLIBRARIES = libgstalaw.la libgstmulaw.la + +libgstalaw_la_SOURCES = alaw-encode.c mulaw-conversion.c alaw-conversion.c alaw-decode.c alaw.c +libgstalaw_la_CFLAGS = $(GST_CFLAGS) + +libgstmulaw_la_SOURCES = mulaw-encode.c mulaw-conversion.c mulaw-decode.c mulaw.c +libgstmulaw_la_CFLAGS = $(GST_CFLAGS) + +noinst_HEADERS = mulaw-conversion.h alaw-encode.h alaw-decode.h alaw-conversion.h mulaw-encode.h mulaw-decode.h +filterdir = $(libdir)/gst diff --git a/gst/law/alaw-conversion.c b/gst/law/alaw-conversion.c new file mode 100644 index 0000000..cb3be3e --- /dev/null +++ b/gst/law/alaw-conversion.c @@ -0,0 +1,195 @@ +/* $Id$ + + * Linux ISDN subsystem, audio conversion and compression (linklevel). + * + * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) + * DTMF code (c) 1996 by Christian Mock (cm@kukuruz.ping.at) + * Silence detection (c) 1998 by Armin Schindler (mac@gismo.telekom.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +/* + * Misc. lookup-tables. + */ + +/* ulaw -> signed 16-bit */ +static gint16 isdn_audio_ulaw_to_s16[] = +{ + 0x8284, 0x8684, 0x8a84, 0x8e84, 0x9284, 0x9684, 0x9a84, 0x9e84, + 0xa284, 0xa684, 0xaa84, 0xae84, 0xb284, 0xb684, 0xba84, 0xbe84, + 0xc184, 0xc384, 0xc584, 0xc784, 0xc984, 0xcb84, 0xcd84, 0xcf84, + 0xd184, 0xd384, 0xd584, 0xd784, 0xd984, 0xdb84, 0xdd84, 0xdf84, + 0xe104, 0xe204, 0xe304, 0xe404, 0xe504, 0xe604, 0xe704, 0xe804, + 0xe904, 0xea04, 0xeb04, 0xec04, 0xed04, 0xee04, 0xef04, 0xf004, + 0xf0c4, 0xf144, 0xf1c4, 0xf244, 0xf2c4, 0xf344, 0xf3c4, 0xf444, + 0xf4c4, 0xf544, 0xf5c4, 0xf644, 0xf6c4, 0xf744, 0xf7c4, 0xf844, + 0xf8a4, 0xf8e4, 0xf924, 0xf964, 0xf9a4, 0xf9e4, 0xfa24, 0xfa64, + 0xfaa4, 0xfae4, 0xfb24, 0xfb64, 0xfba4, 0xfbe4, 0xfc24, 0xfc64, + 0xfc94, 0xfcb4, 0xfcd4, 0xfcf4, 0xfd14, 0xfd34, 0xfd54, 0xfd74, + 0xfd94, 0xfdb4, 0xfdd4, 0xfdf4, 0xfe14, 0xfe34, 0xfe54, 0xfe74, + 0xfe8c, 0xfe9c, 0xfeac, 0xfebc, 0xfecc, 0xfedc, 0xfeec, 0xfefc, + 0xff0c, 0xff1c, 0xff2c, 0xff3c, 0xff4c, 0xff5c, 0xff6c, 0xff7c, + 0xff88, 0xff90, 0xff98, 0xffa0, 0xffa8, 0xffb0, 0xffb8, 0xffc0, + 0xffc8, 0xffd0, 0xffd8, 0xffe0, 0xffe8, 0xfff0, 0xfff8, 0x0000, + 0x7d7c, 0x797c, 0x757c, 0x717c, 0x6d7c, 0x697c, 0x657c, 0x617c, + 0x5d7c, 0x597c, 0x557c, 0x517c, 0x4d7c, 0x497c, 0x457c, 0x417c, + 0x3e7c, 0x3c7c, 0x3a7c, 0x387c, 0x367c, 0x347c, 0x327c, 0x307c, + 0x2e7c, 0x2c7c, 0x2a7c, 0x287c, 0x267c, 0x247c, 0x227c, 0x207c, + 0x1efc, 0x1dfc, 0x1cfc, 0x1bfc, 0x1afc, 0x19fc, 0x18fc, 0x17fc, + 0x16fc, 0x15fc, 0x14fc, 0x13fc, 0x12fc, 0x11fc, 0x10fc, 0x0ffc, + 0x0f3c, 0x0ebc, 0x0e3c, 0x0dbc, 0x0d3c, 0x0cbc, 0x0c3c, 0x0bbc, + 0x0b3c, 0x0abc, 0x0a3c, 0x09bc, 0x093c, 0x08bc, 0x083c, 0x07bc, + 0x075c, 0x071c, 0x06dc, 0x069c, 0x065c, 0x061c, 0x05dc, 0x059c, + 0x055c, 0x051c, 0x04dc, 0x049c, 0x045c, 0x041c, 0x03dc, 0x039c, + 0x036c, 0x034c, 0x032c, 0x030c, 0x02ec, 0x02cc, 0x02ac, 0x028c, + 0x026c, 0x024c, 0x022c, 0x020c, 0x01ec, 0x01cc, 0x01ac, 0x018c, + 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104, + 0x00f4, 0x00e4, 0x00d4, 0x00c4, 0x00b4, 0x00a4, 0x0094, 0x0084, + 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, + 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000 +}; + +/* alaw -> signed 16-bit */ +static gint16 isdn_audio_alaw_to_s16[] = +{ + 0x13fc, 0xec04, 0x0144, 0xfebc, 0x517c, 0xae84, 0x051c, 0xfae4, + 0x0a3c, 0xf5c4, 0x0048, 0xffb8, 0x287c, 0xd784, 0x028c, 0xfd74, + 0x1bfc, 0xe404, 0x01cc, 0xfe34, 0x717c, 0x8e84, 0x071c, 0xf8e4, + 0x0e3c, 0xf1c4, 0x00c4, 0xff3c, 0x387c, 0xc784, 0x039c, 0xfc64, + 0x0ffc, 0xf004, 0x0104, 0xfefc, 0x417c, 0xbe84, 0x041c, 0xfbe4, + 0x083c, 0xf7c4, 0x0008, 0xfff8, 0x207c, 0xdf84, 0x020c, 0xfdf4, + 0x17fc, 0xe804, 0x018c, 0xfe74, 0x617c, 0x9e84, 0x061c, 0xf9e4, + 0x0c3c, 0xf3c4, 0x0084, 0xff7c, 0x307c, 0xcf84, 0x030c, 0xfcf4, + 0x15fc, 0xea04, 0x0164, 0xfe9c, 0x597c, 0xa684, 0x059c, 0xfa64, + 0x0b3c, 0xf4c4, 0x0068, 0xff98, 0x2c7c, 0xd384, 0x02cc, 0xfd34, + 0x1dfc, 0xe204, 0x01ec, 0xfe14, 0x797c, 0x8684, 0x07bc, 0xf844, + 0x0f3c, 0xf0c4, 0x00e4, 0xff1c, 0x3c7c, 0xc384, 0x03dc, 0xfc24, + 0x11fc, 0xee04, 0x0124, 0xfedc, 0x497c, 0xb684, 0x049c, 0xfb64, + 0x093c, 0xf6c4, 0x0028, 0xffd8, 0x247c, 0xdb84, 0x024c, 0xfdb4, + 0x19fc, 0xe604, 0x01ac, 0xfe54, 0x697c, 0x9684, 0x069c, 0xf964, + 0x0d3c, 0xf2c4, 0x00a4, 0xff5c, 0x347c, 0xcb84, 0x034c, 0xfcb4, + 0x12fc, 0xed04, 0x0134, 0xfecc, 0x4d7c, 0xb284, 0x04dc, 0xfb24, + 0x09bc, 0xf644, 0x0038, 0xffc8, 0x267c, 0xd984, 0x026c, 0xfd94, + 0x1afc, 0xe504, 0x01ac, 0xfe54, 0x6d7c, 0x9284, 0x06dc, 0xf924, + 0x0dbc, 0xf244, 0x00b4, 0xff4c, 0x367c, 0xc984, 0x036c, 0xfc94, + 0x0f3c, 0xf0c4, 0x00f4, 0xff0c, 0x3e7c, 0xc184, 0x03dc, 0xfc24, + 0x07bc, 0xf844, 0x0008, 0xfff8, 0x1efc, 0xe104, 0x01ec, 0xfe14, + 0x16fc, 0xe904, 0x0174, 0xfe8c, 0x5d7c, 0xa284, 0x05dc, 0xfa24, + 0x0bbc, 0xf444, 0x0078, 0xff88, 0x2e7c, 0xd184, 0x02ec, 0xfd14, + 0x14fc, 0xeb04, 0x0154, 0xfeac, 0x557c, 0xaa84, 0x055c, 0xfaa4, + 0x0abc, 0xf544, 0x0058, 0xffa8, 0x2a7c, 0xd584, 0x02ac, 0xfd54, + 0x1cfc, 0xe304, 0x01cc, 0xfe34, 0x757c, 0x8a84, 0x075c, 0xf8a4, + 0x0ebc, 0xf144, 0x00d4, 0xff2c, 0x3a7c, 0xc584, 0x039c, 0xfc64, + 0x10fc, 0xef04, 0x0114, 0xfeec, 0x457c, 0xba84, 0x045c, 0xfba4, + 0x08bc, 0xf744, 0x0018, 0xffe8, 0x227c, 0xdd84, 0x022c, 0xfdd4, + 0x18fc, 0xe704, 0x018c, 0xfe74, 0x657c, 0x9a84, 0x065c, 0xf9a4, + 0x0cbc, 0xf344, 0x0094, 0xff6c, 0x327c, 0xcd84, 0x032c, 0xfcd4 +}; + +/* alaw -> ulaw */ +static guint8 isdn_audio_alaw_to_ulaw[] = +{ + 0xab, 0x2b, 0xe3, 0x63, 0x8b, 0x0b, 0xc9, 0x49, + 0xba, 0x3a, 0xf6, 0x76, 0x9b, 0x1b, 0xd7, 0x57, + 0xa3, 0x23, 0xdd, 0x5d, 0x83, 0x03, 0xc1, 0x41, + 0xb2, 0x32, 0xeb, 0x6b, 0x93, 0x13, 0xcf, 0x4f, + 0xaf, 0x2f, 0xe7, 0x67, 0x8f, 0x0f, 0xcd, 0x4d, + 0xbe, 0x3e, 0xfe, 0x7e, 0x9f, 0x1f, 0xdb, 0x5b, + 0xa7, 0x27, 0xdf, 0x5f, 0x87, 0x07, 0xc5, 0x45, + 0xb6, 0x36, 0xef, 0x6f, 0x97, 0x17, 0xd3, 0x53, + 0xa9, 0x29, 0xe1, 0x61, 0x89, 0x09, 0xc7, 0x47, + 0xb8, 0x38, 0xf2, 0x72, 0x99, 0x19, 0xd5, 0x55, + 0xa1, 0x21, 0xdc, 0x5c, 0x81, 0x01, 0xbf, 0x3f, + 0xb0, 0x30, 0xe9, 0x69, 0x91, 0x11, 0xce, 0x4e, + 0xad, 0x2d, 0xe5, 0x65, 0x8d, 0x0d, 0xcb, 0x4b, + 0xbc, 0x3c, 0xfa, 0x7a, 0x9d, 0x1d, 0xd9, 0x59, + 0xa5, 0x25, 0xde, 0x5e, 0x85, 0x05, 0xc3, 0x43, + 0xb4, 0x34, 0xed, 0x6d, 0x95, 0x15, 0xd1, 0x51, + 0xac, 0x2c, 0xe4, 0x64, 0x8c, 0x0c, 0xca, 0x4a, + 0xbb, 0x3b, 0xf8, 0x78, 0x9c, 0x1c, 0xd8, 0x58, + 0xa4, 0x24, 0xde, 0x5e, 0x84, 0x04, 0xc2, 0x42, + 0xb3, 0x33, 0xec, 0x6c, 0x94, 0x14, 0xd0, 0x50, + 0xb0, 0x30, 0xe8, 0x68, 0x90, 0x10, 0xce, 0x4e, + 0xbf, 0x3f, 0xfe, 0x7e, 0xa0, 0x20, 0xdc, 0x5c, + 0xa8, 0x28, 0xe0, 0x60, 0x88, 0x08, 0xc6, 0x46, + 0xb7, 0x37, 0xf0, 0x70, 0x98, 0x18, 0xd4, 0x54, + 0xaa, 0x2a, 0xe2, 0x62, 0x8a, 0x0a, 0xc8, 0x48, + 0xb9, 0x39, 0xf4, 0x74, 0x9a, 0x1a, 0xd6, 0x56, + 0xa2, 0x22, 0xdd, 0x5d, 0x82, 0x02, 0xc0, 0x40, + 0xb1, 0x31, 0xea, 0x6a, 0x92, 0x12, 0xcf, 0x4f, + 0xae, 0x2e, 0xe6, 0x66, 0x8e, 0x0e, 0xcc, 0x4c, + 0xbd, 0x3d, 0xfc, 0x7c, 0x9e, 0x1e, 0xda, 0x5a, + 0xa6, 0x26, 0xdf, 0x5f, 0x86, 0x06, 0xc4, 0x44, + 0xb5, 0x35, 0xee, 0x6e, 0x96, 0x16, 0xd2, 0x52 +}; + +/* ulaw -> alaw */ +static guint8 isdn_audio_ulaw_to_alaw[] = +{ + 0xab, 0x55, 0xd5, 0x15, 0x95, 0x75, 0xf5, 0x35, + 0xb5, 0x45, 0xc5, 0x05, 0x85, 0x65, 0xe5, 0x25, + 0xa5, 0x5d, 0xdd, 0x1d, 0x9d, 0x7d, 0xfd, 0x3d, + 0xbd, 0x4d, 0xcd, 0x0d, 0x8d, 0x6d, 0xed, 0x2d, + 0xad, 0x51, 0xd1, 0x11, 0x91, 0x71, 0xf1, 0x31, + 0xb1, 0x41, 0xc1, 0x01, 0x81, 0x61, 0xe1, 0x21, + 0x59, 0xd9, 0x19, 0x99, 0x79, 0xf9, 0x39, 0xb9, + 0x49, 0xc9, 0x09, 0x89, 0x69, 0xe9, 0x29, 0xa9, + 0xd7, 0x17, 0x97, 0x77, 0xf7, 0x37, 0xb7, 0x47, + 0xc7, 0x07, 0x87, 0x67, 0xe7, 0x27, 0xa7, 0xdf, + 0x9f, 0x7f, 0xff, 0x3f, 0xbf, 0x4f, 0xcf, 0x0f, + 0x8f, 0x6f, 0xef, 0x2f, 0x53, 0x13, 0x73, 0x33, + 0xb3, 0x43, 0xc3, 0x03, 0x83, 0x63, 0xe3, 0x23, + 0xa3, 0x5b, 0xdb, 0x1b, 0x9b, 0x7b, 0xfb, 0x3b, + 0xbb, 0xbb, 0x4b, 0x4b, 0xcb, 0xcb, 0x0b, 0x0b, + 0x8b, 0x8b, 0x6b, 0x6b, 0xeb, 0xeb, 0x2b, 0x2b, + 0xab, 0x54, 0xd4, 0x14, 0x94, 0x74, 0xf4, 0x34, + 0xb4, 0x44, 0xc4, 0x04, 0x84, 0x64, 0xe4, 0x24, + 0xa4, 0x5c, 0xdc, 0x1c, 0x9c, 0x7c, 0xfc, 0x3c, + 0xbc, 0x4c, 0xcc, 0x0c, 0x8c, 0x6c, 0xec, 0x2c, + 0xac, 0x50, 0xd0, 0x10, 0x90, 0x70, 0xf0, 0x30, + 0xb0, 0x40, 0xc0, 0x00, 0x80, 0x60, 0xe0, 0x20, + 0x58, 0xd8, 0x18, 0x98, 0x78, 0xf8, 0x38, 0xb8, + 0x48, 0xc8, 0x08, 0x88, 0x68, 0xe8, 0x28, 0xa8, + 0xd6, 0x16, 0x96, 0x76, 0xf6, 0x36, 0xb6, 0x46, + 0xc6, 0x06, 0x86, 0x66, 0xe6, 0x26, 0xa6, 0xde, + 0x9e, 0x7e, 0xfe, 0x3e, 0xbe, 0x4e, 0xce, 0x0e, + 0x8e, 0x6e, 0xee, 0x2e, 0x52, 0x12, 0x72, 0x32, + 0xb2, 0x42, 0xc2, 0x02, 0x82, 0x62, 0xe2, 0x22, + 0xa2, 0x5a, 0xda, 0x1a, 0x9a, 0x7a, 0xfa, 0x3a, + 0xba, 0xba, 0x4a, 0x4a, 0xca, 0xca, 0x0a, 0x0a, + 0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a +}; + +static inline void +isdn_audio_tlookup(const guint8 *table, guint8 *buff, gulong n) +{ + while (n--) + *buff++ = table[*(unsigned char *)buff]; +} + +void +isdn_audio_ulaw2alaw(guint8 *buff, gulong len) +{ + isdn_audio_tlookup(isdn_audio_ulaw_to_alaw, buff, len); +} + +void +isdn_audio_alaw2ulaw(guint8 *buff, gulong len) +{ + isdn_audio_tlookup(isdn_audio_alaw_to_ulaw, buff, len); +} diff --git a/gst/law/alaw-conversion.h b/gst/law/alaw-conversion.h new file mode 100644 index 0000000..b7d1297 --- /dev/null +++ b/gst/law/alaw-conversion.h @@ -0,0 +1,12 @@ +#ifndef _GST_ALAW_CONVERSION_H +#define _GST_ALAW_CONVERSION_H + +#include + +void +isdn_audio_ulaw2alaw(guint8 *buff, gulong len); + +void +isdn_audio_alaw2ulaw(guint8 *buff, gulong len); + +#endif diff --git a/gst/law/alaw-decode.c b/gst/law/alaw-decode.c new file mode 100644 index 0000000..872d533 --- /dev/null +++ b/gst/law/alaw-decode.c @@ -0,0 +1,186 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + +#include +#include "alaw-decode.h" +#include "mulaw-conversion.h" +#include "alaw-conversion.h" + +extern GstPadTemplate *alawdec_src_template, *alawdec_sink_template; + + +/* Stereo signals and args */ +enum { + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0 +}; + +static void gst_alawdec_class_init (GstALawDecClass *klass); +static void gst_alawdec_init (GstALawDec *alawdec); + +static void gst_alawdec_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void gst_alawdec_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); + +static void gst_alawdec_chain (GstPad *pad, GstBuffer *buf); + + +static GstElementClass *parent_class = NULL; +//static guint gst_stereo_signals[LAST_SIGNAL] = { 0 }; + +static GstPadNegotiateReturn +alawdec_negotiate_sink (GstPad *pad, GstCaps **caps, gint counter) +{ + GstCaps* tempcaps; + + GstALawDec* alawdec=GST_ALAWDEC (GST_OBJECT_PARENT (pad)); + + if (*caps==NULL) + return GST_PAD_NEGOTIATE_FAIL; + + tempcaps = gst_caps_copy(*caps); + + gst_caps_set(tempcaps,"format",GST_PROPS_STRING("int")); + gst_caps_set(tempcaps,"law",GST_PROPS_INT(0)); + gst_caps_set(tempcaps,"depth",GST_PROPS_INT(16)); + gst_caps_set(tempcaps,"width",GST_PROPS_INT(16)); + gst_caps_set(tempcaps,"signed",GST_PROPS_BOOLEAN(TRUE)); + + if (gst_pad_set_caps (alawdec->srcpad, tempcaps)) + { + return GST_PAD_NEGOTIATE_AGREE; + } + else { + gst_caps_unref (tempcaps); + return GST_PAD_NEGOTIATE_FAIL; + } +} + +GType +gst_alawdec_get_type(void) { + static GType alawdec_type = 0; + + if (!alawdec_type) { + static const GTypeInfo alawdec_info = { + sizeof(GstALawDecClass), NULL, + NULL, + (GClassInitFunc)gst_alawdec_class_init, + NULL, + NULL, + sizeof(GstALawDec), + 0, + (GInstanceInitFunc)gst_alawdec_init, + }; + alawdec_type = g_type_register_static(GST_TYPE_ELEMENT, "GstALawDec", &alawdec_info, 0); + } + return alawdec_type; +} + +static void +gst_alawdec_class_init (GstALawDecClass *klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass*)klass; + gstelement_class = (GstElementClass*)klass; + + parent_class = g_type_class_ref(GST_TYPE_ELEMENT); + + gobject_class->set_property = gst_alawdec_set_property; + gobject_class->get_property = gst_alawdec_get_property; +} + +static void +gst_alawdec_init (GstALawDec *alawdec) +{ + alawdec->sinkpad = gst_pad_new_from_template(alawdec_sink_template,"sink"); + alawdec->srcpad = gst_pad_new_from_template(alawdec_src_template,"src"); + gst_pad_set_negotiate_function(alawdec->sinkpad, alawdec_negotiate_sink); + + gst_element_add_pad(GST_ELEMENT(alawdec),alawdec->sinkpad); + gst_pad_set_chain_function(alawdec->sinkpad,gst_alawdec_chain); + gst_element_add_pad(GST_ELEMENT(alawdec),alawdec->srcpad); +} + +static void +gst_alawdec_chain (GstPad *pad,GstBuffer *buf) +{ + GstALawDec *alawdec; + gint16 *linear_data; + guint8 *alaw_data; + GstBuffer* outbuf; + + g_return_if_fail(pad != NULL); + g_return_if_fail(GST_IS_PAD(pad)); + g_return_if_fail(buf != NULL); + + alawdec = GST_ALAWDEC(GST_OBJECT_PARENT (pad)); + g_return_if_fail(alawdec != NULL); + g_return_if_fail(GST_IS_ALAWDEC(alawdec)); + + alaw_data = (guint8 *)GST_BUFFER_DATA(buf); + outbuf=gst_buffer_new(); + GST_BUFFER_DATA(outbuf) = (gchar*)g_new(gint16,GST_BUFFER_SIZE(buf)); + GST_BUFFER_SIZE(outbuf) = GST_BUFFER_SIZE(buf)*2; + + linear_data = (gint16*)GST_BUFFER_DATA(outbuf); + + isdn_audio_alaw2ulaw(alaw_data,GST_BUFFER_SIZE(buf)); + mulaw_decode(alaw_data,linear_data,GST_BUFFER_SIZE(buf)); + + gst_buffer_unref(buf); + gst_pad_push(alawdec->srcpad,outbuf); +} + +static void +gst_alawdec_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstALawDec *alawdec; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_ALAWDEC(object)); + alawdec = GST_ALAWDEC(object); + + switch (prop_id) { + default: + break; + } +} + +static void +gst_alawdec_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstALawDec *alawdec; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_ALAWDEC(object)); + alawdec = GST_ALAWDEC(object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + diff --git a/gst/law/alaw-decode.h b/gst/law/alaw-decode.h new file mode 100644 index 0000000..f487009 --- /dev/null +++ b/gst/law/alaw-decode.h @@ -0,0 +1,69 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + + +#ifndef __GST_ALAWDECODE_H__ +#define __GST_ALAWDECODE_H__ + + +#include +#include +// #include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GST_TYPE_ALAWDEC \ + (gst_alawdec_get_type()) +#define GST_ALAWDEC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALAWDEC,GstALawDec)) +#define GST_ALAWDEC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALAWDEC,GstALawDec)) +#define GST_IS_ALAWDEC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALAWDEC)) +#define GST_IS_ALAWDEC_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALAWDEC)) + +typedef struct _GstALawDec GstALawDec; +typedef struct _GstALawDecClass GstALawDecClass; + +struct _GstALawDec { + GstElement element; + + GstPad *sinkpad,*srcpad; + + //MetaAudioRaw meta; + +}; + +struct _GstALawDecClass { + GstElementClass parent_class; +}; + +GType gst_alawdec_get_type(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_STEREO_H__ */ diff --git a/gst/law/alaw-encode.c b/gst/law/alaw-encode.c new file mode 100644 index 0000000..ab54bd1 --- /dev/null +++ b/gst/law/alaw-encode.c @@ -0,0 +1,182 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + +#include +#include "alaw-encode.h" +#include "mulaw-conversion.h" +#include "alaw-conversion.h" + +extern GstPadTemplate *alawenc_src_template, *alawenc_sink_template; + + +/* Stereo signals and args */ +enum { + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0 +}; + +static void gst_alawenc_class_init (GstALawEncClass *klass); +static void gst_alawenc_init (GstALawEnc *alawenc); + +static void gst_alawenc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void gst_alawenc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); + +static void gst_alawenc_chain (GstPad *pad, GstBuffer *buf); + + +static GstElementClass *parent_class = NULL; +//static guint gst_stereo_signals[LAST_SIGNAL] = { 0 }; + +static GstPadNegotiateReturn +alawenc_negotiate_sink (GstPad *pad, GstCaps **caps, gint counter) +{ + GstCaps* tempcaps; + + GstALawEnc* alawenc=GST_ALAWENC (GST_OBJECT_PARENT (pad)); + + if (*caps==NULL) + return GST_PAD_NEGOTIATE_FAIL; + + tempcaps = gst_caps_copy(*caps); + + gst_caps_set(tempcaps,"format",GST_PROPS_STRING("int")); + gst_caps_set(tempcaps,"law",GST_PROPS_INT(2)); + gst_caps_set(tempcaps,"depth",GST_PROPS_INT(8)); + gst_caps_set(tempcaps,"width",GST_PROPS_INT(8)); + gst_caps_set(tempcaps,"signed",GST_PROPS_BOOLEAN(FALSE)); + + if (gst_pad_set_caps (alawenc->srcpad, tempcaps)) + { + return GST_PAD_NEGOTIATE_AGREE; + } + else { + gst_caps_unref (tempcaps); + return GST_PAD_NEGOTIATE_FAIL; + } +} + +GType +gst_alawenc_get_type(void) { + static GType alawenc_type = 0; + + if (!alawenc_type) { + static const GTypeInfo alawenc_info = { + sizeof(GstALawEncClass), NULL, + NULL, + (GClassInitFunc)gst_alawenc_class_init, + NULL, + NULL, + sizeof(GstALawEnc), + 0, + (GInstanceInitFunc)gst_alawenc_init, + }; + alawenc_type = g_type_register_static(GST_TYPE_ELEMENT, "GstALawEnc", &alawenc_info, 0); + } + return alawenc_type; +} + +static void +gst_alawenc_class_init (GstALawEncClass *klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass*)klass; + gstelement_class = (GstElementClass*)klass; + + parent_class = g_type_class_ref(GST_TYPE_ELEMENT); + + gobject_class->set_property = gst_alawenc_set_property; + gobject_class->get_property = gst_alawenc_get_property; +} + +static void +gst_alawenc_init (GstALawEnc *alawenc) +{ + alawenc->sinkpad = gst_pad_new_from_template(alawenc_sink_template,"sink"); + alawenc->srcpad = gst_pad_new_from_template(alawenc_src_template,"src"); + gst_pad_set_negotiate_function(alawenc->sinkpad, alawenc_negotiate_sink); + + gst_element_add_pad(GST_ELEMENT(alawenc),alawenc->sinkpad); + gst_pad_set_chain_function(alawenc->sinkpad,gst_alawenc_chain); + gst_element_add_pad(GST_ELEMENT(alawenc),alawenc->srcpad); +} + +static void +gst_alawenc_chain (GstPad *pad,GstBuffer *buf) +{ + GstALawEnc *alawenc; + gint16 *linear_data; + guint8 *alaw_data; + GstBuffer* outbuf; + + g_return_if_fail(pad != NULL); + g_return_if_fail(GST_IS_PAD(pad)); + g_return_if_fail(buf != NULL); + + alawenc = GST_ALAWENC(GST_OBJECT_PARENT (pad)); + g_return_if_fail(alawenc != NULL); + g_return_if_fail(GST_IS_ALAWENC(alawenc)); + + linear_data = (gint16 *)GST_BUFFER_DATA(buf); + outbuf=gst_buffer_new(); + GST_BUFFER_DATA(outbuf) = (gchar*)g_new(gint16,GST_BUFFER_SIZE(buf)/4); + GST_BUFFER_SIZE(outbuf) = GST_BUFFER_SIZE(buf)/2; + + alaw_data = (guint8*)GST_BUFFER_DATA(outbuf); + mulaw_encode(linear_data,alaw_data,GST_BUFFER_SIZE(outbuf)); + isdn_audio_ulaw2alaw(alaw_data,GST_BUFFER_SIZE(outbuf)); + gst_buffer_unref(buf); + gst_pad_push(alawenc->srcpad,outbuf); +} + +static void +gst_alawenc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstALawEnc *alawenc; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_ALAWENC(object)); + alawenc = GST_ALAWENC(object); + + switch (prop_id) { + default: + break; + } +} + +static void +gst_alawenc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstALawEnc *alawenc; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_ALAWENC(object)); + alawenc = GST_ALAWENC(object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} diff --git a/gst/law/alaw-encode.h b/gst/law/alaw-encode.h new file mode 100644 index 0000000..023d063 --- /dev/null +++ b/gst/law/alaw-encode.h @@ -0,0 +1,69 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + + +#ifndef __GST_ALAWENCODE_H__ +#define __GST_ALAWENCODE_H__ + + +#include +#include +// #include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GST_TYPE_ALAWENC \ + (gst_alawenc_get_type()) +#define GST_ALAWENC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALAWENC,GstALawEnc)) +#define GST_ALAWENC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALAWENC,GstALawEnc)) +#define GST_IS_ALAWENC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALAWENC)) +#define GST_IS_ALAWENC_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALAWENC)) + +typedef struct _GstALawEnc GstALawEnc; +typedef struct _GstALawEncClass GstALawEncClass; + +struct _GstALawEnc { + GstElement element; + + GstPad *sinkpad,*srcpad; + + //MetaAudioRaw meta; + +}; + +struct _GstALawEncClass { + GstElementClass parent_class; +}; + +GType gst_alawenc_get_type(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_STEREO_H__ */ diff --git a/gst/law/alaw.c b/gst/law/alaw.c new file mode 100644 index 0000000..1b9afb5 --- /dev/null +++ b/gst/law/alaw.c @@ -0,0 +1,95 @@ +#include "alaw-encode.h" +#include "alaw-decode.h" + +static GstElementDetails alawenc_details = { + "PCM to A Law conversion", + "Filter/Effect", + "Convert 16bit PCM to 8bit A law", + VERSION, + "Zaheer Merali ", + "(C) 2001" +}; + +static GstElementDetails alawdec_details = { + "A Law to PCM conversion", + "Filter/Effect", + "Convert 8bit A law to 16bit PCM", + VERSION, + "Zaheer Merali ", + "(C) 2001" +}; + +static GstCaps* +alaw_factory (void) +{ + return + gst_caps_new ( + "test_src", + "audio/raw", + gst_props_new ( + "format", GST_PROPS_STRING ("int"), + "law", GST_PROPS_INT (2), + "width", GST_PROPS_INT(8), + "depth", GST_PROPS_INT(8), + "signed", GST_PROPS_BOOLEAN(FALSE), + NULL)); +} + +static GstCaps* +linear_factory (void) +{ + return + gst_caps_new ( + "test_sink", + "audio/raw", + gst_props_new ( + "format", GST_PROPS_STRING ("int"), + "law", GST_PROPS_INT(0), + "width", GST_PROPS_INT(16), + "depth", GST_PROPS_INT(16), + "signed", GST_PROPS_BOOLEAN(TRUE), + NULL)); +} + +GstPadTemplate *alawenc_src_template, *alawenc_sink_template; +GstPadTemplate *alawdec_src_template, *alawdec_sink_template; + +static gboolean +plugin_init (GModule *module, GstPlugin *plugin) +{ + GstElementFactory *alawenc_factory, *alawdec_factory; + GstCaps* alaw_caps, *linear_caps; + + alawenc_factory = gst_elementfactory_new("alawencode",GST_TYPE_ALAWENC, + &alawenc_details); + g_return_val_if_fail(alawenc_factory != NULL, FALSE); + alawdec_factory = gst_elementfactory_new("alawdecode",GST_TYPE_ALAWDEC, + &alawdec_details); + g_return_val_if_fail(alawdec_factory != NULL, FALSE); + + alaw_caps = alaw_factory (); + linear_caps = linear_factory (); + + alawenc_src_template = gst_padtemplate_new ("src",GST_PAD_SRC,GST_PAD_ALWAYS,alaw_caps, NULL); + alawenc_sink_template = gst_padtemplate_new ("sink",GST_PAD_SINK,GST_PAD_ALWAYS,linear_caps, NULL); + gst_elementfactory_add_padtemplate (alawenc_factory, alawenc_src_template); + gst_elementfactory_add_padtemplate (alawenc_factory, alawenc_sink_template); + + alawdec_src_template = gst_padtemplate_new ("src",GST_PAD_SRC,GST_PAD_ALWAYS,linear_caps, NULL); + alawdec_sink_template = gst_padtemplate_new ("sink",GST_PAD_SINK,GST_PAD_ALWAYS,alaw_caps, NULL); + + gst_elementfactory_add_padtemplate (alawdec_factory, alawdec_src_template); + gst_elementfactory_add_padtemplate (alawdec_factory, alawdec_sink_template); + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (alawenc_factory)); + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (alawdec_factory)); + + return TRUE; +} + +GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "alaw", + plugin_init +}; + diff --git a/gst/law/mulaw-conversion.c b/gst/law/mulaw-conversion.c new file mode 100644 index 0000000..ad3fcce --- /dev/null +++ b/gst/law/mulaw-conversion.c @@ -0,0 +1,102 @@ +/* + * This routine converts from linear to ulaw + * 29 September 1989 + * + * Craig Reese: IDA/Supercomputing Research Center + * Joe Campbell: Department of Defense + * + * References: + * 1) CCITT Recommendation G.711 (very difficult to follow) + * 2) "A New Digital Technique for Implementation of Any + * Continuous PCM Companding Law," Villeret, Michel, + * et al. 1973 IEEE Int. Conf. on Communications, Vol 1, + * 1973, pg. 11.12-11.17 + * 3) MIL-STD-188-113,"Interoperability and Performance Standards + * for Analog-to_Digital Conversion Techniques," + * 17 February 1987 + * + * Input: Signed 16 bit linear sample + * Output: 8 bit ulaw sample + */ + +#include + +#define ZEROTRAP /* turn on the trap as per the MIL-STD */ +#define BIAS 0x84 /* define the add-in bias for 16 bit samples */ +#define CLIP 32635 + +void +mulaw_encode(gint16* in, guint8* out, gint numsamples) +{ + static gint16 exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7}; + gint16 sign, exponent, mantissa,i; + gint16 sample; + guint8 ulawbyte; + + for(i=0;i> 8) & 0x80; /* set aside the sign */ + if (sign != 0) sample = -sample; /* get magnitude */ + if (sample > CLIP) sample = CLIP; /* clip the magnitude */ + /** convert from 16 bit linear to ulaw **/ + sample = sample + BIAS; + exponent = exp_lut[(sample>>7) & 0xFF]; + mantissa = (sample >> (exponent+3)) & 0x0F; + ulawbyte = ~(sign | (exponent << 4) | mantissa); +#ifdef ZEROTRAP + if (ulawbyte == 0 ) ulawbyte = 0x02; /* optional CCITT trap */ +#endif + out[i]=ulawbyte; + } +} + +/* + * This routine converts from ulaw to 16 bit linear + * 29 September 1989 + * + * Craig Reese: IDA/Supercomputing Research Center + * + * References: + * 1) CCITT Recommendation G.711 (very difficult to follow) + * 2) MIL-STD-188-113,"Interoperability and Performance Standards + * for Analog-to_Digital Conversion Techniques," + * 17 February 1987 + * + * Input: 8 bit ulaw sample + * Output: signed 16 bit linear sample + */ + +void +mulaw_decode(guint8* in,gint16* out,gint numsamples) +{ + static gint16 exp_lut[8]={0,132,396,924,1980,4092,8316,16764}; + gint16 sign, exponent, mantissa; + guint8 ulawbyte; + gint16 linear,i; + for(i=0;i> 4) & 0x07; + mantissa = ulawbyte & 0x0F; + linear = exp_lut[exponent] + (mantissa << (exponent+3)); + if (sign != 0) linear = -linear; + out[i]=linear; + } +} diff --git a/gst/law/mulaw-conversion.h b/gst/law/mulaw-conversion.h new file mode 100644 index 0000000..5518012 --- /dev/null +++ b/gst/law/mulaw-conversion.h @@ -0,0 +1,10 @@ +#ifndef _GST_ULAWDECODE_H +#define _GST_ULAWDECODE_H + +#include + +void +mulaw_encode(gint16* in, guint8* out, gint numsamples); +void +mulaw_decode(guint8* in,gint16* out,gint numsamples); +#endif diff --git a/gst/law/mulaw-decode.c b/gst/law/mulaw-decode.c new file mode 100644 index 0000000..d93c690 --- /dev/null +++ b/gst/law/mulaw-decode.c @@ -0,0 +1,181 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + +#include +#include "mulaw-decode.h" +#include "mulaw-conversion.h" + +extern GstPadTemplate *mulawdec_src_template, *mulawdec_sink_template; + + +/* Stereo signals and args */ +enum { + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0 +}; + +static void gst_mulawdec_class_init (GstMuLawDecClass *klass); +static void gst_mulawdec_init (GstMuLawDec *mulawdec); + +static void gst_mulawdec_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void gst_mulawdec_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); + +static void gst_mulawdec_chain (GstPad *pad, GstBuffer *buf); + + +static GstElementClass *parent_class = NULL; +//static guint gst_stereo_signals[LAST_SIGNAL] = { 0 }; + +static GstPadNegotiateReturn +mulawdec_negotiate_sink (GstPad *pad, GstCaps **caps, gint counter) +{ + GstCaps* tempcaps; + + GstMuLawDec* mulawdec=GST_MULAWDEC (GST_OBJECT_PARENT (pad)); + + if (*caps==NULL) + return GST_PAD_NEGOTIATE_FAIL; + + tempcaps = gst_caps_copy(*caps); + + gst_caps_set(tempcaps,"format",GST_PROPS_STRING("int")); + gst_caps_set(tempcaps,"law",GST_PROPS_INT(0)); + gst_caps_set(tempcaps,"depth",GST_PROPS_INT(16)); + gst_caps_set(tempcaps,"width",GST_PROPS_INT(16)); + gst_caps_set(tempcaps,"signed",GST_PROPS_BOOLEAN(TRUE)); + + if (gst_pad_set_caps (mulawdec->srcpad, tempcaps)) + { + return GST_PAD_NEGOTIATE_AGREE; + } + else { + gst_caps_unref (tempcaps); + return GST_PAD_NEGOTIATE_FAIL; + } +} + +GType +gst_mulawdec_get_type(void) { + static GType mulawdec_type = 0; + + if (!mulawdec_type) { + static const GTypeInfo mulawdec_info = { + sizeof(GstMuLawDecClass), NULL, + NULL, + (GClassInitFunc)gst_mulawdec_class_init, + NULL, + NULL, + sizeof(GstMuLawDec), + 0, + (GInstanceInitFunc)gst_mulawdec_init, + }; + mulawdec_type = g_type_register_static(GST_TYPE_ELEMENT, "GstMuLawDec", &mulawdec_info, 0); + } + return mulawdec_type; +} + +static void +gst_mulawdec_class_init (GstMuLawDecClass *klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass*)klass; + gstelement_class = (GstElementClass*)klass; + + parent_class = g_type_class_ref(GST_TYPE_ELEMENT); + + gobject_class->set_property = gst_mulawdec_set_property; + gobject_class->get_property = gst_mulawdec_get_property; +} + +static void +gst_mulawdec_init (GstMuLawDec *mulawdec) +{ + mulawdec->sinkpad = gst_pad_new_from_template(mulawdec_sink_template,"sink"); + mulawdec->srcpad = gst_pad_new_from_template(mulawdec_src_template,"src"); + gst_pad_set_negotiate_function(mulawdec->sinkpad, mulawdec_negotiate_sink); + + gst_element_add_pad(GST_ELEMENT(mulawdec),mulawdec->sinkpad); + gst_pad_set_chain_function(mulawdec->sinkpad,gst_mulawdec_chain); + gst_element_add_pad(GST_ELEMENT(mulawdec),mulawdec->srcpad); +} + +static void +gst_mulawdec_chain (GstPad *pad,GstBuffer *buf) +{ + GstMuLawDec *mulawdec; + gint16 *linear_data; + guint8 *mulaw_data; + GstBuffer* outbuf; + + g_return_if_fail(pad != NULL); + g_return_if_fail(GST_IS_PAD(pad)); + g_return_if_fail(buf != NULL); + + mulawdec = GST_MULAWDEC(GST_OBJECT_PARENT (pad)); + g_return_if_fail(mulawdec != NULL); + g_return_if_fail(GST_IS_MULAWDEC(mulawdec)); + + mulaw_data = (guint8 *)GST_BUFFER_DATA(buf); + outbuf=gst_buffer_new(); + GST_BUFFER_DATA(outbuf) = (gchar*)g_new(gint16,GST_BUFFER_SIZE(buf)); + GST_BUFFER_SIZE(outbuf) = GST_BUFFER_SIZE(buf)*2; + + linear_data = (gint16*)GST_BUFFER_DATA(outbuf); + mulaw_decode(mulaw_data,linear_data,GST_BUFFER_SIZE(buf)); + + gst_buffer_unref(buf); + gst_pad_push(mulawdec->srcpad,outbuf); +} + +static void +gst_mulawdec_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstMuLawDec *mulawdec; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_MULAWDEC(object)); + mulawdec = GST_MULAWDEC(object); + + switch (prop_id) { + default: + break; + } +} + +static void +gst_mulawdec_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstMuLawDec *mulawdec; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_MULAWDEC(object)); + mulawdec = GST_MULAWDEC(object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} diff --git a/gst/law/mulaw-decode.h b/gst/law/mulaw-decode.h new file mode 100644 index 0000000..431b1bd --- /dev/null +++ b/gst/law/mulaw-decode.h @@ -0,0 +1,69 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + + +#ifndef __GST_MULAWDECODE_H__ +#define __GST_MULAWDECODE_H__ + + +#include +#include +// #include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GST_TYPE_MULAWDEC \ + (gst_mulawdec_get_type()) +#define GST_MULAWDEC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MULAWDEC,GstMuLawDec)) +#define GST_MULAWDEC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MULAWDEC,GstMuLawDec)) +#define GST_IS_MULAWDEC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MULAWDEC)) +#define GST_IS_MULAWDEC_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MULAWDEC)) + +typedef struct _GstMuLawDec GstMuLawDec; +typedef struct _GstMuLawDecClass GstMuLawDecClass; + +struct _GstMuLawDec { + GstElement element; + + GstPad *sinkpad,*srcpad; + + //MetaAudioRaw meta; + +}; + +struct _GstMuLawDecClass { + GstElementClass parent_class; +}; + +GType gst_mulawdec_get_type(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_STEREO_H__ */ diff --git a/gst/law/mulaw-encode.c b/gst/law/mulaw-encode.c new file mode 100644 index 0000000..40d868d --- /dev/null +++ b/gst/law/mulaw-encode.c @@ -0,0 +1,181 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + +#include +#include "mulaw-encode.h" +#include "mulaw-conversion.h" + +extern GstPadTemplate *mulawenc_src_template, *mulawenc_sink_template; + + +/* Stereo signals and args */ +enum { + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0 +}; + +static void gst_mulawenc_class_init (GstMuLawEncClass *klass); +static void gst_mulawenc_init (GstMuLawEnc *mulawenc); + +static void gst_mulawenc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void gst_mulawenc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); + +static void gst_mulawenc_chain (GstPad *pad, GstBuffer *buf); + + +static GstElementClass *parent_class = NULL; +//static guint gst_stereo_signals[LAST_SIGNAL] = { 0 }; + +static GstPadNegotiateReturn +mulawenc_negotiate_sink (GstPad *pad, GstCaps **caps, gint counter) +{ + GstCaps* tempcaps; + + GstMuLawEnc* mulawenc=GST_MULAWENC (GST_OBJECT_PARENT (pad)); + + if (*caps==NULL) + return GST_PAD_NEGOTIATE_FAIL; + + tempcaps = gst_caps_copy(*caps); + + gst_caps_set(tempcaps,"format",GST_PROPS_STRING("int")); + gst_caps_set(tempcaps,"law",GST_PROPS_INT(1)); + gst_caps_set(tempcaps,"depth",GST_PROPS_INT(8)); + gst_caps_set(tempcaps,"width",GST_PROPS_INT(8)); + gst_caps_set(tempcaps,"signed",GST_PROPS_BOOLEAN(FALSE)); + + if (gst_pad_set_caps (mulawenc->srcpad, tempcaps)) + { + return GST_PAD_NEGOTIATE_AGREE; + } + else { + gst_caps_unref (tempcaps); + return GST_PAD_NEGOTIATE_FAIL; + } +} + +GType +gst_mulawenc_get_type(void) { + static GType mulawenc_type = 0; + + if (!mulawenc_type) { + static const GTypeInfo mulawenc_info = { + sizeof(GstMuLawEncClass), NULL, + NULL, + (GClassInitFunc)gst_mulawenc_class_init, + NULL, + NULL, + sizeof(GstMuLawEnc), + 0, + (GInstanceInitFunc)gst_mulawenc_init, + }; + mulawenc_type = g_type_register_static(GST_TYPE_ELEMENT, "GstMuLawEnc", &mulawenc_info, 0); + } + return mulawenc_type; +} + +static void +gst_mulawenc_class_init (GstMuLawEncClass *klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass*)klass; + gstelement_class = (GstElementClass*)klass; + + parent_class = g_type_class_ref(GST_TYPE_ELEMENT); + + gobject_class->set_property = gst_mulawenc_set_property; + gobject_class->get_property = gst_mulawenc_get_property; +} + +static void +gst_mulawenc_init (GstMuLawEnc *mulawenc) +{ + mulawenc->sinkpad = gst_pad_new_from_template(mulawenc_sink_template,"sink"); + mulawenc->srcpad = gst_pad_new_from_template(mulawenc_src_template,"src"); + gst_pad_set_negotiate_function(mulawenc->sinkpad, mulawenc_negotiate_sink); + + gst_element_add_pad(GST_ELEMENT(mulawenc),mulawenc->sinkpad); + gst_pad_set_chain_function(mulawenc->sinkpad,gst_mulawenc_chain); + gst_element_add_pad(GST_ELEMENT(mulawenc),mulawenc->srcpad); +} + +static void +gst_mulawenc_chain (GstPad *pad,GstBuffer *buf) +{ + GstMuLawEnc *mulawenc; + gint16 *linear_data; + guint8 *mulaw_data; + GstBuffer* outbuf; + + g_return_if_fail(pad != NULL); + g_return_if_fail(GST_IS_PAD(pad)); + g_return_if_fail(buf != NULL); + + mulawenc = GST_MULAWENC(GST_OBJECT_PARENT (pad)); + g_return_if_fail(mulawenc != NULL); + g_return_if_fail(GST_IS_MULAWENC(mulawenc)); + + linear_data = (gint16 *)GST_BUFFER_DATA(buf); + outbuf=gst_buffer_new(); + GST_BUFFER_DATA(outbuf) = (gchar*)g_new(gint16,GST_BUFFER_SIZE(buf)/4); + GST_BUFFER_SIZE(outbuf) = GST_BUFFER_SIZE(buf)/2; + + mulaw_data = (gint8*)GST_BUFFER_DATA(outbuf); + mulaw_encode(linear_data,mulaw_data,GST_BUFFER_SIZE(outbuf)); + + gst_buffer_unref(buf); + gst_pad_push(mulawenc->srcpad,outbuf); +} + +static void +gst_mulawenc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstMuLawEnc *mulawenc; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_MULAWENC(object)); + mulawenc = GST_MULAWENC(object); + + switch (prop_id) { + default: + break; + } +} + +static void +gst_mulawenc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstMuLawEnc *mulawenc; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_MULAWENC(object)); + mulawenc = GST_MULAWENC(object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} diff --git a/gst/law/mulaw-encode.h b/gst/law/mulaw-encode.h new file mode 100644 index 0000000..009b470 --- /dev/null +++ b/gst/law/mulaw-encode.h @@ -0,0 +1,69 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + + +#ifndef __GST_MULAWENCODE_H__ +#define __GST_MULAWENCODE_H__ + + +#include +#include +// #include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GST_TYPE_MULAWENC \ + (gst_mulawenc_get_type()) +#define GST_MULAWENC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MULAWENC,GstMuLawEnc)) +#define GST_MULAWENC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MULAWENC,GstMuLawEnc)) +#define GST_IS_MULAWENC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MULAWENC)) +#define GST_IS_MULAWENC_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MULAWENC)) + +typedef struct _GstMuLawEnc GstMuLawEnc; +typedef struct _GstMuLawEncClass GstMuLawEncClass; + +struct _GstMuLawEnc { + GstElement element; + + GstPad *sinkpad,*srcpad; + + //MetaAudioRaw meta; + +}; + +struct _GstMuLawEncClass { + GstElementClass parent_class; +}; + +GType gst_mulawenc_get_type(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_STEREO_H__ */ diff --git a/gst/law/mulaw.c b/gst/law/mulaw.c new file mode 100644 index 0000000..5b97eca --- /dev/null +++ b/gst/law/mulaw.c @@ -0,0 +1,103 @@ +#include "mulaw-encode.h" +#include "mulaw-decode.h" + +static GstElementDetails mulawenc_details = { + "PCM to Mu Law conversion", + "Filter/Effect", + "Convert 16bit PCM to 8bit mu law", + VERSION, + "Zaheer Merali ", + "(C) 2001" +}; + +static GstElementDetails mulawdec_details = { + "Mu Law to PCM conversion", + "Filter/Effect", + "Convert 8bit mu law to 16bit PCM", + VERSION, + "Zaheer Merali ", + "(C) 2001" +}; + +static GstCaps* +mulaw_factory (void) +{ + return + gst_caps_new ( + "test_src", + "audio/raw", + gst_props_new ( + "format", GST_PROPS_STRING ("int"), + "law", GST_PROPS_INT (1), + "width", GST_PROPS_INT(8), + "depth", GST_PROPS_INT(8), + "signed", GST_PROPS_BOOLEAN(FALSE), + NULL)); +} + +static GstCaps* +linear_factory (void) +{ + return + gst_caps_new ( + "test_sink", + "audio/raw", + gst_props_new ( + "format", GST_PROPS_STRING ("int"), + "law", GST_PROPS_INT(0), + "width", GST_PROPS_INT(16), + "depth", GST_PROPS_INT(16), + "signed", GST_PROPS_BOOLEAN(TRUE), + NULL)); +} + +GstPadTemplate *mulawenc_src_template, *mulawenc_sink_template; +GstPadTemplate *mulawdec_src_template, *mulawdec_sink_template; + +static gboolean +plugin_init (GModule *module, GstPlugin *plugin) +{ + GstElementFactory *mulawenc_factory, *mulawdec_factory; + GstCaps* mulaw_caps, *linear_caps; + + mulawenc_factory = gst_elementfactory_new("mulawencode",GST_TYPE_MULAWENC, + &mulawenc_details); + g_return_val_if_fail(mulawenc_factory != NULL, FALSE); + mulawdec_factory = gst_elementfactory_new("mulawdecode",GST_TYPE_MULAWDEC, + &mulawdec_details); + g_return_val_if_fail(mulawdec_factory != NULL, FALSE); + + mulaw_caps = mulaw_factory (); + linear_caps = linear_factory (); + + mulawenc_src_template = gst_padtemplate_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, + mulaw_caps, NULL); + mulawenc_sink_template = gst_padtemplate_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, + linear_caps, NULL); + + gst_elementfactory_add_padtemplate (mulawenc_factory, mulawenc_src_template); + gst_elementfactory_add_padtemplate (mulawenc_factory, mulawenc_sink_template); + + mulawdec_src_template = gst_padtemplate_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, + linear_caps, NULL); + mulawdec_sink_template = gst_padtemplate_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, + mulaw_caps, NULL); + + gst_elementfactory_add_padtemplate (mulawdec_factory, mulawdec_src_template); + gst_elementfactory_add_padtemplate (mulawdec_factory, mulawdec_sink_template); + + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (mulawenc_factory)); + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (mulawdec_factory)); + + + + return TRUE; +} + +GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "mulaw", + plugin_init +}; + diff --git a/gst/level/Makefile.am b/gst/level/Makefile.am new file mode 100644 index 0000000..df87d6c --- /dev/null +++ b/gst/level/Makefile.am @@ -0,0 +1,10 @@ +filterdir = $(libdir)/gst + +filter_LTLIBRARIES = libgstlevel.la + +libgstlevel_la_SOURCES = gstlevel.c +libgstlevel_la_CFLAGS = $(GST_CFLAGS) + +noinst_HEADERS = gstlevel.h filter.func + +EXTRA_DIST = README diff --git a/gst/level/README b/gst/level/README new file mode 100644 index 0000000..c7dbf4c --- /dev/null +++ b/gst/level/README @@ -0,0 +1,11 @@ +level plugin by thomas + +basic level indicator; prints out RMS values averaged over the buffer of +one iteration. Insert this into an audio/raw chain. + +You can plot the level envelope of the track using gnuplot, example : + +tools/gstreamer-launch disksrc location=foo.wav ! parsewav ! level ! \ + fakesink silent=true > foo.level +graph -T gif foo.level > foo.gif +xview dark.gif diff --git a/gst/level/filter.func b/gst/level/filter.func new file mode 100644 index 0000000..ccdaf61 --- /dev/null +++ b/gst/level/filter.func @@ -0,0 +1,45 @@ +{ + guint j; + double squaresum = 0.0; + double RMS = 0.0; + double RMS_dB = 0.0; + static int threshold_dB = -80; + static long int sample = 0; + double timepoint; + + /* + * process data here + * input sample data enters in *in_data as 8 or 16 bit data + * samples for left and right channel are interleaved + */ +/* + for(j = 0; j < num_samples; j++) { + (*out_data)[j] = in_data[j]; + squaresum += in_data[j] * in_data[j]; + } + RMS = sqrt (squaresum / (float) num_samples); + printf ("RMS for this block : %f\n", RMS); + RMS_dB = 20 * log (RMS / 32767); + printf ("RMS in dB (for 16bit) : %f\n", RMS_dB); +*/ + + for(j = 0; j < num_samples; j++) { + (*out_data)[j] = in_data[j]; + squaresum += pow ((double) in_data[j] / 32767.0, 2); + } + RMS = sqrt (squaresum / (float) num_samples); + RMS_dB = 10 * log (RMS); + sample += num_samples; + timepoint = sample / (44100.0 * 2); + + if (RMS_dB > (double) threshold_dB) + { +/* printf ("Reached %d dB at %f sec (%f dB)\n", + threshold_dB, timepoint, RMS_dB); +*/ + threshold_dB += 1; + } +/* printf ("RMS in dB (for 16bit) : %f\n", RMS_dB); */ + printf ("%f %f\n", timepoint, RMS_dB); +} + diff --git a/gst/level/gstlevel.c b/gst/level/gstlevel.c new file mode 100644 index 0000000..cd839a3 --- /dev/null +++ b/gst/level/gstlevel.c @@ -0,0 +1,285 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + +#include +#include "gstlevel.h" +#include "math.h" + + +static GstElementDetails level_details = { + "Level", + "Filter/Effect", + "RMS Level indicator for audio/raw", + VERSION, + "Thomas ", + "(C) 2001", +}; + + +/* Filter signals and args */ +enum { + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0 +}; + +static GstPadTemplate* +level_src_factory (void) +{ + static GstPadTemplate *template = NULL; + + if (!template) { + template = gst_padtemplate_new ( + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + gst_caps_new ( + "test_src", + "audio/raw", + gst_props_new ( + "channels", GST_PROPS_INT_RANGE (1, 2), + NULL)), + NULL); + } + return template; +} + +static GstPadTemplate* +level_sink_factory (void) +{ + static GstPadTemplate *template = NULL; + + if (!template) { + template = gst_padtemplate_new ( + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + gst_caps_new ( + "test_src", + "audio/raw", + gst_props_new ( + "channels", GST_PROPS_INT_RANGE (1, 2), + NULL)), + NULL); + } + return template; +} + +static void gst_level_class_init (GstLevelClass *klass); +static void gst_level_init (GstLevel *filter); + +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, GstBuffer *buf); +static void inline gst_level_fast_16bit_chain (gint16* data, gint16** out_data, + guint numsamples); +static void inline gst_level_fast_8bit_chain (gint8* data, gint8** out_data, + guint numsamples); + +static GstElementClass *parent_class = NULL; +//static guint gst_filter_signals[LAST_SIGNAL] = { 0 }; + +static GstPadNegotiateReturn +level_negotiate_src (GstPad *pad, GstCaps **caps, gpointer *data) +{ + GstLevel* filter = GST_LEVEL (gst_pad_get_parent (pad)); + + if (*caps==NULL) + return GST_PAD_NEGOTIATE_FAIL; + + return gst_pad_negotiate_proxy(pad,filter->sinkpad,caps); +} + +static GstPadNegotiateReturn +level_negotiate_sink (GstPad *pad, GstCaps **caps, gpointer *data) +{ + GstLevel* filter = GST_LEVEL (gst_pad_get_parent (pad)); + + if (*caps==NULL) + return GST_PAD_NEGOTIATE_FAIL; + + return gst_pad_negotiate_proxy(pad,filter->srcpad,caps); +} + +GType +gst_level_get_type(void) { + static GType level_type = 0; + + if (!level_type) { + static const GTypeInfo level_info = { + sizeof(GstLevelClass), NULL, + 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); + } + return level_type; +} + +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); + + gobject_class->set_property = gst_level_set_property; + gobject_class->get_property = gst_level_get_property; +} + +static void +gst_level_init (GstLevel *filter) +{ + filter->sinkpad = gst_pad_new_from_template(level_sink_factory (),"sink"); + filter->srcpad = gst_pad_new_from_template(level_src_factory (),"src"); + + gst_pad_set_negotiate_function(filter->sinkpad,level_negotiate_sink); + gst_pad_set_negotiate_function(filter->srcpad,level_negotiate_src); + + gst_element_add_pad(GST_ELEMENT(filter),filter->sinkpad); + gst_pad_set_chain_function(filter->sinkpad,gst_level_chain); + filter->srcpad = gst_pad_new("src",GST_PAD_SRC); + gst_element_add_pad(GST_ELEMENT(filter),filter->srcpad); +} + +static void +gst_level_chain (GstPad *pad,GstBuffer *buf) +{ + GstLevel *filter; + gint16 *in_data; + gint16 *out_data; + GstBuffer* outbuf; + gint width; + + GstCaps *caps; + + 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)); + + caps = NULL; + caps = GST_PAD_CAPS(pad); + if (caps == NULL) + { + // FIXME : Please change this to a better warning method ! + printf ("WARNING : chain : Could not get caps of pad !\n"); + } + + width = gst_caps_get_int(caps, "width"); + + in_data = (gint16 *)GST_BUFFER_DATA(buf); + outbuf=gst_buffer_new(); + GST_BUFFER_DATA(outbuf) = (gchar*)g_new(gint16,GST_BUFFER_SIZE(buf)/2); + GST_BUFFER_SIZE(outbuf) = GST_BUFFER_SIZE(buf); + + out_data = (gint16*)GST_BUFFER_DATA(outbuf); + + switch (width) { + case 16: + gst_level_fast_16bit_chain(in_data,&out_data,GST_BUFFER_SIZE(buf)/2); + break; + case 8: + gst_level_fast_8bit_chain((gint8*)in_data,(gint8**)&out_data,GST_BUFFER_SIZE(buf)); + break; + } + gst_buffer_unref(buf); + gst_pad_push(filter->srcpad,outbuf); +} + +static void inline +gst_level_fast_16bit_chain(gint16* in_data, gint16** out_data, + guint num_samples) +#include "filter.func" + +static void inline +gst_level_fast_8bit_chain(gint8* in_data, gint8** out_data, + guint num_samples) +#include "filter.func" + +static void +gst_level_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstLevel *filter; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_LEVEL(object)); + filter = GST_LEVEL(object); + + switch (prop_id) { + default: + break; + } +} + +static void +gst_level_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstLevel *filter; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_LEVEL(object)); + filter = GST_LEVEL(object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +plugin_init (GModule *module, GstPlugin *plugin) +{ + GstElementFactory *factory; + + factory = gst_elementfactory_new("level",GST_TYPE_LEVEL, + &level_details); + g_return_val_if_fail(factory != NULL, FALSE); + + gst_elementfactory_add_padtemplate (factory, level_src_factory ()); + gst_elementfactory_add_padtemplate (factory, level_sink_factory ()); + + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); + + return TRUE; +} + +GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "level", + plugin_init +}; diff --git a/gst/level/gstlevel.h b/gst/level/gstlevel.h new file mode 100644 index 0000000..f9dade0 --- /dev/null +++ b/gst/level/gstlevel.h @@ -0,0 +1,69 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + + +#ifndef __GST_LEVEL_H__ +#define __GST_LEVEL_H__ + + +#include +#include +// #include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GST_TYPE_LEVEL \ + (gst_level_get_type()) +#define GST_LEVEL(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_LEVEL,GstLevel)) +#define GST_LEVEL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ULAW,GstLevel)) +#define GST_IS_LEVEL(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_LEVEL)) +#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; + + GstPad *sinkpad,*srcpad; + + //MetaAudioRaw meta; + +}; + +struct _GstLevelClass { + GstElementClass parent_class; +}; + +GType gst_level_get_type(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_STEREO_H__ */ diff --git a/gst/median/.gitignore b/gst/median/.gitignore new file mode 100644 index 0000000..08f5ed3 --- /dev/null +++ b/gst/median/.gitignore @@ -0,0 +1,7 @@ +Makefile +Makefile.in +*.o +*.lo +*.la +.deps +.libs diff --git a/gst/median/Makefile.am b/gst/median/Makefile.am new file mode 100644 index 0000000..cf75f34 --- /dev/null +++ b/gst/median/Makefile.am @@ -0,0 +1,9 @@ +filterdir = $(libdir)/gst + +filter_LTLIBRARIES = libgstmedian.la + +libgstmedian_la_SOURCES = gstmedian.c + +libgstmedian_la_CFLAGS = -O3 $(FOMIT_FRAME_POINTER) -funroll-all-loops -finline-functions -ffast-math $(GST_CFLAGS) + +noinst_HEADERS = gstmedian.h diff --git a/gst/median/gstmedian.c b/gst/median/gstmedian.c new file mode 100644 index 0000000..f0e836a --- /dev/null +++ b/gst/median/gstmedian.c @@ -0,0 +1,412 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + +#include +#include + + +static GstElementDetails median_details = { + "Median effect", + "Filter/Effect", + "apply a median filter to an image", + VERSION, + "Wim Taymans ", + "(C) 2000", +}; + +GST_PADTEMPLATE_FACTORY (median_src_factory, + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "median_src", + "video/raw", + "format", GST_PROPS_FOURCC (GST_STR_FOURCC ("I420")) + ) +) + +GST_PADTEMPLATE_FACTORY (median_sink_factory, + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "median_src", + "video/raw", + "format", GST_PROPS_FOURCC (GST_STR_FOURCC ("I420")) + ) +) + + +/* Median signals and args */ +enum { + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0, + ARG_ACTIVE, + ARG_FILTERSIZE, + ARG_LUM_ONLY +}; + +static GType gst_median_get_type (void); +static void gst_median_class_init (GstMedianClass *klass); +static void gst_median_init (GstMedian *median); + +static void median_5 (unsigned char *src, unsigned char *dest, int height, int width); +static void median_9 (unsigned char *src, unsigned char *dest, int height, int width); +static void gst_median_chain (GstPad *pad, GstBuffer *buf); + +static void gst_median_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void gst_median_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); + +static GstElementClass *parent_class = NULL; +//static guint gst_median_signals[LAST_SIGNAL] = { 0 }; + +static GstPadNegotiateReturn +median_negotiate_src (GstPad *pad, GstCaps **caps, gpointer *data) +{ + GstMedian* filter = GST_MEDIAN (gst_pad_get_parent (pad)); + + if (*caps==NULL) + return GST_PAD_NEGOTIATE_FAIL; + + return gst_pad_negotiate_proxy (pad, filter->sinkpad, caps); +} + +static GstPadNegotiateReturn +median_negotiate_sink (GstPad *pad, GstCaps **caps, gpointer *data) +{ + GstMedian* filter = GST_MEDIAN (gst_pad_get_parent (pad)); + + if (*caps==NULL) + return GST_PAD_NEGOTIATE_FAIL; + + return gst_pad_negotiate_proxy (pad, filter->srcpad, caps); +} + +GType +gst_median_get_type (void) +{ + static GType median_type = 0; + + if (!median_type) { + static const GTypeInfo median_info = { + sizeof(GstMedianClass), NULL, NULL, (GClassInitFunc)gst_median_class_init, + NULL, + NULL, + sizeof(GstMedian), + 0, + (GInstanceInitFunc)gst_median_init, + }; + median_type = g_type_register_static(GST_TYPE_ELEMENT, "GstMedian", &median_info, 0); + } + return median_type; +} + +static void +gst_median_class_init (GstMedianClass *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_ACTIVE, + g_param_spec_boolean("active","active","active", + TRUE,G_PARAM_READWRITE)); // CHECKME + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FILTERSIZE, + g_param_spec_int("filtersize","filtersize","filtersize", + G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_LUM_ONLY, + g_param_spec_boolean("lum_only","lum_only","lum_only", + TRUE,G_PARAM_READWRITE)); // CHECKME + + gobject_class->set_property = gst_median_set_property; + gobject_class->get_property = gst_median_get_property; +} + +static void +gst_median_newcaps (GstPad *pad, GstCaps *caps) +{ + GstMedian *filter; + + filter = GST_MEDIAN (gst_pad_get_parent (pad)); + + filter->width = gst_caps_get_int (caps, "width"); + filter->height = gst_caps_get_int (caps, "height"); +} + +void gst_median_init (GstMedian *median) +{ + median->sinkpad = gst_pad_new_from_template ( + GST_PADTEMPLATE_GET (median_sink_factory), "sink"); + gst_pad_set_negotiate_function (median->sinkpad, median_negotiate_sink); + gst_pad_set_newcaps_function (median->sinkpad, gst_median_newcaps); + gst_pad_set_chain_function (median->sinkpad, gst_median_chain); + gst_element_add_pad (GST_ELEMENT (median), median->sinkpad); + + median->srcpad = gst_pad_new_from_template ( + GST_PADTEMPLATE_GET (median_src_factory), "src"); + gst_pad_set_negotiate_function (median->srcpad, median_negotiate_src); + gst_element_add_pad (GST_ELEMENT (median), median->srcpad); + + median->filtersize = 5; + median->lum_only = TRUE; + median->active = TRUE; +} + +#define PIX_SORT(a,b) { if ((a)>(b)) PIX_SWAP((a),(b)); } +#define PIX_SWAP(a,b) { unsigned char temp=(a);(a)=(b);(b)=temp; } + +static void +median_5 (unsigned char *src, unsigned char *dest, int width, int height) +{ + int nLastRow; + int nLastCol; + unsigned char p[9]; + int i, j, k; + + nLastCol = width - 1; + nLastRow = height - 1; + + //copy the top and bottom rows into the result array + for (i=0; iactive) { + gst_pad_push(median->srcpad,buf); + return; + } + + data = GST_BUFFER_DATA(buf); + size = GST_BUFFER_SIZE(buf); + + GST_DEBUG (0,"median: have buffer of %d\n", GST_BUFFER_SIZE(buf)); + + outbuf = gst_buffer_new(); + GST_BUFFER_DATA(outbuf) = g_malloc(GST_BUFFER_SIZE(buf)); + GST_BUFFER_SIZE(outbuf) = GST_BUFFER_SIZE(buf); + + lumsize = median->width * median->height; + chromsize = lumsize/4; + + if (median->filtersize == 5) { + median_5(data, GST_BUFFER_DATA(outbuf), median->width, median->height); + if (!median->lum_only) { + median_5(data+lumsize, GST_BUFFER_DATA(outbuf)+lumsize, median->width/2, median->height/2); + median_5(data+lumsize+chromsize, GST_BUFFER_DATA(outbuf)+lumsize+chromsize, median->width/2, median->height/2); + } + else { + memcpy (GST_BUFFER_DATA (outbuf)+lumsize, data+lumsize, chromsize*2); + } + } + else { + median_9(data, GST_BUFFER_DATA(outbuf), median->width, median->height); + if (!median->lum_only) { + median_9(data+lumsize, GST_BUFFER_DATA(outbuf)+lumsize, median->width/2, median->height/2); + median_9(data+lumsize+chromsize, GST_BUFFER_DATA(outbuf)+lumsize+chromsize, median->width/2, median->height/2); + } + else { + memcpy (GST_BUFFER_DATA (outbuf)+lumsize, data+lumsize, chromsize*2); + } + } + GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf); + + gst_buffer_unref(buf); + + gst_pad_push(median->srcpad,outbuf); +} + +static void +gst_median_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstMedian *median; + gint argvalue; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_MEDIAN(object)); + median = GST_MEDIAN(object); + + switch (prop_id) { + case ARG_FILTERSIZE: + argvalue = g_value_get_int (value); + if (argvalue != 5 && argvalue != 9) { + g_warning ("median: invalid filtersize (%d), must be 5 or 9\n", argvalue); + } + else { + median->filtersize = argvalue; + } + break; + case ARG_ACTIVE: + median->active = g_value_get_boolean (value); + break; + case ARG_LUM_ONLY: + median->lum_only = g_value_get_boolean (value); + break; + default: + break; + } +} + +static void +gst_median_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstMedian *median; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_MEDIAN(object)); + median = GST_MEDIAN(object); + + switch (prop_id) { + case ARG_FILTERSIZE: + g_value_set_int (value, median->filtersize); + break; + case ARG_ACTIVE: + g_value_set_boolean (value, median->active); + break; + case ARG_LUM_ONLY: + g_value_set_boolean (value, median->lum_only); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + +static gboolean +plugin_init (GModule *module, GstPlugin *plugin) +{ + GstElementFactory *factory; + + factory = gst_elementfactory_new("median",GST_TYPE_MEDIAN, + &median_details); + g_return_val_if_fail(factory != NULL, FALSE); + + gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (median_sink_factory)); + gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (median_src_factory)); + + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); + + return TRUE; +} + +GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "median", + plugin_init +}; + diff --git a/gst/median/gstmedian.h b/gst/median/gstmedian.h new file mode 100644 index 0000000..17c7d04 --- /dev/null +++ b/gst/median/gstmedian.h @@ -0,0 +1,72 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + + +#ifndef __GST_MEDIAN_H__ +#define __GST_MEDIAN_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GST_TYPE_MEDIAN \ + (gst_median_get_type()) +#define GST_MEDIAN(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MEDIAN,GstMedian)) +#define GST_MEDIAN_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MEDIAN,GstMedian)) +#define GST_IS_MEDIAN(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MEDIAN)) +#define GST_IS_MEDIAN_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MEDIAN)) + +typedef struct _GstMedian GstMedian; +typedef struct _GstMedianClass GstMedianClass; + +struct _GstMedian { + GstElement element; + + int format; + int width; + int height; + + int filtersize; + + gboolean active; + gboolean lum_only; + + GstPad *sinkpad,*srcpad; +}; + +struct _GstMedianClass { + GstElementClass parent_class; +}; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_MEDIAN_H__ */ diff --git a/gst/spectrum/.gitignore b/gst/spectrum/.gitignore new file mode 100644 index 0000000..08f5ed3 --- /dev/null +++ b/gst/spectrum/.gitignore @@ -0,0 +1,7 @@ +Makefile +Makefile.in +*.o +*.lo +*.la +.deps +.libs diff --git a/gst/spectrum/Makefile.am b/gst/spectrum/Makefile.am new file mode 100644 index 0000000..476c3fd --- /dev/null +++ b/gst/spectrum/Makefile.am @@ -0,0 +1,10 @@ +filterdir = $(libdir)/gst + +filter_LTLIBRARIES = libgstspectrum.la + +libgstspectrum_la_SOURCES = gstspectrum.c fix_fft.c +libgstspectrum_la_CFLAGS = $(GST_CFLAGS) + +noinst_HEADERS = gstspectrum.h + +EXTRA_DIST = README diff --git a/gst/spectrum/README b/gst/spectrum/README new file mode 100644 index 0000000..8755571 --- /dev/null +++ b/gst/spectrum/README @@ -0,0 +1,5 @@ +This is a simple, rather lame spectrum analyzer made from the fix_fft.c +code, as found I think in xmms-0.9.1 (the 75-wide output sounds like xmms +to me), which is actually written by other people (see fix_fft.c for +credits). It worked last time I had GiST working, which was a while ago. +Yes, GiST is not included here yet, it will be in 0.1.0. diff --git a/gst/spectrum/gstspectrum.c b/gst/spectrum/gstspectrum.c new file mode 100644 index 0000000..0821545 --- /dev/null +++ b/gst/spectrum/gstspectrum.c @@ -0,0 +1,242 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + +#include + +#include "gstspectrum.h" + +static GstElementDetails gst_spectrum_details = { + "Spectrum analyzer", + "Filter/Analysis", + "Run an FFT on the audio signal, output spectrum data", + VERSION, + "Erik Walthinsen ", + "(C) 1999", +}; + + +static GstTypeDefinition spectrumdefinition = { + "spectrum_spectrum_raw", + "spectrum/raw", + NULL, + NULL, +}; + + +/* Spectrum signals and args */ +enum { + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0, + ARG_WIDTH, +}; + + +static void gst_spectrum_class_init (GstSpectrumClass *klass); +static void gst_spectrum_init (GstSpectrum *spectrum); + +static void gst_spectrum_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); + +static void gst_spectrum_chain (GstPad *pad, GstBuffer *buf); + +#define fixed short +int gst_spectrum_fix_fft(fixed fr[], fixed fi[], int m, int inverse); +void gst_spectrum_fix_loud(fixed loud[], fixed fr[], fixed fi[], int n, int scale_shift); +void gst_spectrum_window(fixed fr[], int n); + + +static GstElementClass *parent_class = NULL; +//static guint gst_spectrum_signals[LAST_SIGNAL] = { 0 }; + +GType +gst_spectrum_get_type (void) +{ + static GType spectrum_type = 0; + + if (!spectrum_type) { + static const GTypeInfo spectrum_info = { + sizeof(GstSpectrumClass), NULL, + NULL, + (GClassInitFunc)gst_spectrum_class_init, + NULL, + NULL, + sizeof(GstSpectrum), + 0, + (GInstanceInitFunc)gst_spectrum_init, + }; + spectrum_type = g_type_register_static(GST_TYPE_ELEMENT, "GstSpectrum", &spectrum_info, 0); + } + return spectrum_type; +} + +static void +gst_spectrum_class_init (GstSpectrumClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = (GObjectClass*)klass; + + parent_class = g_type_class_ref(GST_TYPE_ELEMENT); + + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_WIDTH, + g_param_spec_int("width","width","width", + G_MININT,G_MAXINT,0,G_PARAM_WRITABLE)); // CHECKME + + gobject_class->set_property = gst_spectrum_set_property; +} + +static void +gst_spectrum_init (GstSpectrum *spectrum) +{ + spectrum->sinkpad = gst_pad_new("sink",GST_PAD_SINK); + gst_element_add_pad(GST_ELEMENT(spectrum),spectrum->sinkpad); + gst_pad_set_chain_function(spectrum->sinkpad,gst_spectrum_chain); + spectrum->srcpad = gst_pad_new("src",GST_PAD_SRC); + gst_element_add_pad(GST_ELEMENT(spectrum),spectrum->srcpad); + + spectrum->width = 75; +} + +static void +gst_spectrum_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstSpectrum *spectrum; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_SPECTRUM(object)); + spectrum = GST_SPECTRUM(object); + + switch (prop_id) { + case ARG_WIDTH: + spectrum->width = g_value_get_int (value); + break; + default: + break; + } +} + +static void +gst_spectrum_chain (GstPad *pad, GstBuffer *buf) +{ + GstSpectrum *spectrum; + gint spec_base, spec_len; + gint16 *re, *im, *loud; + gint16 *samples; + gint samplecount,step,pos,i; + guchar *spect; + GstBuffer *newbuf; + + g_return_if_fail(pad != NULL); + g_return_if_fail(GST_IS_PAD(pad)); + g_return_if_fail(buf != NULL); + + spectrum = GST_SPECTRUM (GST_OBJECT_PARENT (pad)); + + /* first deal with audio metadata */ +// FIXME +// if (buf->meta) { +// if (spectrum->meta != NULL) { +// /* FIXME: need to unref the old metadata so it goes away */ +// } +// /* we just make a copy of the pointer */ +// spectrum->meta = (MetaAudioRaw *)(buf->data); +// /* FIXME: now we have to ref the metadata so it does go away */ +// } + + //g_return_if_fail(spectrum->meta != NULL); + + //samplecount = GST_BUFFER_SIZE(buf) / + // (spectrum->meta->channels * sizeof(gint16)); +// samples = (gint16 *)g_malloc(buf->datasize); +// g_return_if_fail(samples != NULL); +// memcpy(samples,(gint16 +//*)GST_BUFFER_DATA(buf),GST_BUFFER_DATASIZE(buf)); +// gst_buffer_unref(buf); + samples = (gint16 *)GST_BUFFER_DATA(buf); + +// return; +// spec_base = (gint) (log(samplecount) / log(2)); +// if (spec_base > 10) spec_base = 10; +// spec_len = (gint) pow(2, spec_base); + spec_base = 8; + spec_len = 1024; + + im = g_malloc(spec_len * sizeof(gint16)); + g_return_if_fail(im != NULL); + loud = g_malloc(spec_len * sizeof(gint16)); + g_return_if_fail(loud != NULL); + + memset(im,0,spec_len * sizeof(gint16)); + //if (spectrum->meta->channels == 2) { + re = g_malloc(spec_len * sizeof(gint16)); + for (i=0;i> 1; + //} else + // re = samples; + gst_spectrum_window(re,spec_len); + gst_spectrum_fix_fft(re,im,spec_base,FALSE); + gst_spectrum_fix_loud(loud,re,im,spec_len,0); + if (re != samples) g_free(re); + g_free(im); + step = spec_len / (spectrum->width*2); + spect = (guchar *)g_malloc(spectrum->width); + for (i=0,pos=0;iwidth;i++,pos += step) { + if (loud[pos] > -60) + spect[i] = (loud[pos] + 60) / 2; + else + spect[i] = 0; +// if (spect[i] > 15); +// spect[i] = 15; + } + g_free(loud); + gst_buffer_unref(buf); +// g_free(samples); + + newbuf = gst_buffer_new(); + g_return_if_fail(newbuf != NULL); + GST_BUFFER_DATA(newbuf) = spect; + GST_BUFFER_SIZE(newbuf) = spectrum->width; + + gst_pad_push(spectrum->srcpad,newbuf); +} + +static gboolean +plugin_init (GModule *module, GstPlugin *plugin) +{ + GstElementFactory *factory; + + /* create an elementfactory for the spectrum element */ + factory = gst_elementfactory_new ("spectrum",GST_TYPE_SPECTRUM, + &gst_spectrum_details); + g_return_val_if_fail (factory != NULL, FALSE); + + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); + + return TRUE; +} + +GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "spectrum", + plugin_init +}; diff --git a/gst/spectrum/gstspectrum.h b/gst/spectrum/gstspectrum.h new file mode 100644 index 0000000..f7a395e --- /dev/null +++ b/gst/spectrum/gstspectrum.h @@ -0,0 +1,67 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + + +#ifndef __GST_SPECTRUM_H__ +#define __GST_SPECTRUM_H__ + + +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GST_TYPE_SPECTRUM \ + (gst_spectrum_get_type()) +#define GST_SPECTRUM(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SPECTRUM,GstSpectrum)) +#define GST_SPECTRUM_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SPECTRUM,GstSpectrum)) +#define GST_IS_SPECTRUM(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SPECTRUM)) +#define GST_IS_SPECTRUM_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SPECTRUM)) + +typedef struct _GstSpectrum GstSpectrum; +typedef struct _GstSpectrumClass GstSpectrumClass; + +struct _GstSpectrum { + GstElement element; + + GstPad *sinkpad,*srcpad; + + gint width; +}; + +struct _GstSpectrumClass { + GstElementClass parent_class; +}; + +GType gst_spectrum_get_type(void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_SPECTRUM_H__ */ diff --git a/gst/udp/.gitignore b/gst/udp/.gitignore new file mode 100644 index 0000000..08f5ed3 --- /dev/null +++ b/gst/udp/.gitignore @@ -0,0 +1,7 @@ +Makefile +Makefile.in +*.o +*.lo +*.la +.deps +.libs diff --git a/gst/udp/Makefile.am b/gst/udp/Makefile.am new file mode 100644 index 0000000..0cd25aa --- /dev/null +++ b/gst/udp/Makefile.am @@ -0,0 +1,10 @@ +filterdir = $(libdir)/gst + +filter_LTLIBRARIES = libgstudp.la + +libgstudp_la_SOURCES = gstudp.c gstudpsrc.c gstudpsink.c +libgstudp_la_CFLAGS = $(GST_CFLAGS) + +noinst_HEADERS = gstudpsink.h gstudpsrc.h + +EXTRA_DIST = README diff --git a/gst/udp/README b/gst/udp/README new file mode 100644 index 0000000..e032e74 --- /dev/null +++ b/gst/udp/README @@ -0,0 +1,28 @@ +* What is UDP src/sink? + +This plugin is *not* meant to be a professional stream broadcast +solution, like icecast or realaudio or whatever. + +This plugin is basically for testing and simple hacks: raw audio +or packetized gsm should be fine. + + +* Shortcomings + +Even given our modest ambitions, the current code is doesn't handle +caps negotiation robustly. + + +* Todo + +This plugin should offer different modes for caps negotiation: none, +udp, or tcp. The udp mode should include the caps every five packets +(approx). The tcp mode can do bi-directional negotiation. + +Perhaps this plugin can be the example of how to do caps negotiation +via a point-to-point protocol. + + +12 Sep 2001 +Wim Taymans +Joshua N Pritikin diff --git a/gst/udp/gstudp.c b/gst/udp/gstudp.c new file mode 100644 index 0000000..8bea987 --- /dev/null +++ b/gst/udp/gstudp.c @@ -0,0 +1,52 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + + +#include "gstudpsrc.h" +#include "gstudpsink.h" + +/* elementfactory information */ +extern GstElementDetails gst_udpsrc_details; +extern GstElementDetails gst_udpsink_details; + +static gboolean +plugin_init (GModule *module, GstPlugin *plugin) +{ + GstElementFactory *src, *sink; + + /* create an elementfactory for the udpsrc element */ + sink = gst_elementfactory_new ("udpsink",GST_TYPE_UDPSINK, + &gst_udpsink_details); + g_return_val_if_fail (sink != NULL, FALSE); + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (sink)); + + src = gst_elementfactory_new ("udpsrc",GST_TYPE_UDPSRC, + &gst_udpsrc_details); + g_return_val_if_fail (src != NULL, FALSE); + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (src)); + + return TRUE; +} + +GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "udp", + plugin_init +}; diff --git a/gst/udp/gstudpsink.c b/gst/udp/gstudpsink.c new file mode 100644 index 0000000..81d7a95 --- /dev/null +++ b/gst/udp/gstudpsink.c @@ -0,0 +1,301 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + + +#include "gstudpsink.h" + +#define UDP_DEFAULT_HOST "localhost" +#define UDP_DEFAULT_PORT 4951 + +/* elementfactory information */ +GstElementDetails gst_udpsink_details = { + "UDP packet sender", + "Transport/", + "", + VERSION, + "Wim Taymans ", + "(C) 2001", +}; + +/* UDPSink signals and args */ +enum { + FRAME_ENCODED, + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0, + ARG_HOST, + ARG_PORT, + /* FILL ME */ +}; + +static void gst_udpsink_class_init (GstUDPSink *klass); +static void gst_udpsink_init (GstUDPSink *udpsink); + +static void gst_udpsink_chain (GstPad *pad,GstBuffer *buf); +static GstElementStateReturn gst_udpsink_change_state (GstElement *element); + +static void gst_udpsink_set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec); +static void gst_udpsink_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec); + + +static GstElementClass *parent_class = NULL; +//static guint gst_udpsink_signals[LAST_SIGNAL] = { 0 }; + +GType +gst_udpsink_get_type (void) +{ + static GType udpsink_type = 0; + + + if (!udpsink_type) { + static const GTypeInfo udpsink_info = { + sizeof(GstUDPSinkClass), + NULL, + NULL, + (GClassInitFunc)gst_udpsink_class_init, + NULL, + NULL, + sizeof(GstUDPSink), + 0, + (GInstanceInitFunc)gst_udpsink_init, + NULL + }; + udpsink_type = g_type_register_static (GST_TYPE_ELEMENT, "GstUDPSink", &udpsink_info, 0); + } + return udpsink_type; +} + +static void +gst_udpsink_class_init (GstUDPSink *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_HOST, + g_param_spec_string ("host", "nost", "The host to send the packets to", + UDP_DEFAULT_HOST, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PORT, + g_param_spec_int ("port", "port", "The port to send the packets to", + 0, 32768, UDP_DEFAULT_PORT, G_PARAM_READWRITE)); + + gobject_class->set_property = gst_udpsink_set_property; + gobject_class->get_property = gst_udpsink_get_property; + + gstelement_class->change_state = gst_udpsink_change_state; +} + + +static void +gst_udpsink_newcaps (GstPad *pad, GstCaps *caps) +{ + GstUDPSink *udpsink; + struct sockaddr_in serv_addr; + struct hostent *serverhost; + int fd; + FILE *f; +#ifndef GST_DISABLE_LOADSAVE + xmlDocPtr doc; +#endif + + udpsink = GST_UDPSINK (gst_pad_get_parent (pad)); + + fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (fd < 0) { + perror("socket"); + return; + } + memset(&serv_addr, 0, sizeof(serv_addr)); + /* its a name rather than an ipnum */ + serverhost = gethostbyname(udpsink->host); + if (serverhost == (struct hostent *)0) { + perror("gethostbyname"); + return; + } + memmove(&serv_addr.sin_addr,serverhost->h_addr, serverhost->h_length); + + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(udpsink->port); + + if (connect(fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) != 0) { + g_printerr ("udpsink: connect to %s port %d failed: %s\n", + udpsink->host, udpsink->port, sys_errlist[errno]); + return; + } + f = fdopen (dup (fd), "wb"); + +#ifndef GST_DISABLE_LOADSAVE + doc = xmlNewDoc ("1.0"); + doc->xmlRootNode = xmlNewDocNode (doc, NULL, "NewCaps", NULL); + + gst_caps_save_thyself (caps, doc->xmlRootNode); + xmlDocDump(f, doc); +#endif + + fclose (f); + close (fd); +} + +static void +gst_udpsink_init (GstUDPSink *udpsink) +{ + /* create the sink and src pads */ + udpsink->sinkpad = gst_pad_new ("sink", GST_PAD_SINK); + gst_element_add_pad (GST_ELEMENT (udpsink), udpsink->sinkpad); + gst_pad_set_chain_function (udpsink->sinkpad, gst_udpsink_chain); + gst_pad_set_newcaps_function (udpsink->sinkpad, gst_udpsink_newcaps); + + udpsink->host = g_strdup (UDP_DEFAULT_HOST); + udpsink->port = UDP_DEFAULT_PORT; +} + +static void +gst_udpsink_chain (GstPad *pad, GstBuffer *buf) +{ + GstUDPSink *udpsink; + int tolen; + + g_return_if_fail (pad != NULL); + g_return_if_fail (GST_IS_PAD (pad)); + g_return_if_fail (buf != NULL); + + udpsink = GST_UDPSINK (GST_OBJECT_PARENT (pad)); + + tolen = sizeof(udpsink->theiraddr); + + if (sendto (udpsink->sock, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), 0, + (struct sockaddr *) &udpsink->theiraddr, tolen) == -1) + { + perror("sending"); + } + + gst_buffer_unref(buf); +} + +static void +gst_udpsink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstUDPSink *udpsink; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_UDPSINK(object)); + udpsink = GST_UDPSINK(object); + + switch (prop_id) { + case ARG_HOST: + if (udpsink->host != NULL) g_free(udpsink->host); + if (g_value_get_string (value) == NULL) + udpsink->host = NULL; + else + udpsink->host = g_strdup (g_value_get_string (value)); + break; + case ARG_PORT: + udpsink->port = g_value_get_int (value); + break; + default: + break; + } +} + +static void +gst_udpsink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstUDPSink *udpsink; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_UDPSINK(object)); + udpsink = GST_UDPSINK(object); + + switch (prop_id) { + case ARG_HOST: + g_value_set_string (value, udpsink->host); + break; + case ARG_PORT: + g_value_set_int (value, udpsink->port); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + +// create a socket for sending to remote machine +static gboolean +gst_udpsink_init_send (GstUDPSink *sink) +{ + struct hostent *he; + + bzero (&sink->theiraddr, sizeof (sink->theiraddr)); + sink->theiraddr.sin_family = AF_INET; // host byte order + sink->theiraddr.sin_port = htons (sink->port); // short, network byte order + if ((he = gethostbyname (sink->host)) == NULL) { + perror("gethostbyname"); + return FALSE; + } + sink->theiraddr.sin_addr = *((struct in_addr *) he->h_addr); + + if ((sink->sock = socket (AF_INET, SOCK_DGRAM, 0)) == -1) { + perror("socket"); + return FALSE; + } + + GST_FLAG_SET (sink, GST_UDPSINK_OPEN); + + return TRUE; +} + +static void +gst_udpsink_close (GstUDPSink *sink) +{ + close (sink->sock); + + GST_FLAG_UNSET (sink, GST_UDPSINK_OPEN); +} + +static GstElementStateReturn +gst_udpsink_change_state (GstElement *element) +{ + g_return_val_if_fail (GST_IS_UDPSINK (element), GST_STATE_FAILURE); + + if (GST_STATE_PENDING (element) == GST_STATE_NULL) { + if (GST_FLAG_IS_SET (element, GST_UDPSINK_OPEN)) + gst_udpsink_close (GST_UDPSINK (element)); + } else { + if (!GST_FLAG_IS_SET (element, GST_UDPSINK_OPEN)) { + if (!gst_udpsink_init_send (GST_UDPSINK (element))) + return GST_STATE_FAILURE; + } + } + + if (GST_ELEMENT_CLASS (parent_class)->change_state) + return GST_ELEMENT_CLASS (parent_class)->change_state (element); + + return GST_STATE_SUCCESS; +} + diff --git a/gst/udp/gstudpsink.h b/gst/udp/gstudpsink.h new file mode 100644 index 0000000..4a7c335 --- /dev/null +++ b/gst/udp/gstudpsink.h @@ -0,0 +1,91 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + + +#ifndef __GST_UDPSINK_H__ +#define __GST_UDPSINK_H__ + + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GST_TYPE_UDPSINK \ + (gst_udpsink_get_type()) +#define GST_UDPSINK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_UDPSINK,GstUDPSink)) +#define GST_UDPSINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_UDPSINK,GstUDPSink)) +#define GST_IS_UDPSINK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_UDPSINK)) +#define GST_IS_UDPSINK_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_UDPSINK)) + +typedef struct _GstUDPSink GstUDPSink; +typedef struct _GstUDPSinkClass GstUDPSinkClass; + +typedef enum { + GST_UDPSINK_OPEN = GST_ELEMENT_FLAG_LAST, + + GST_UDPSINK_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 2, +} GstUDPSinkFlags; + +struct _GstUDPSink { + GstElement element; + + /* pads */ + GstPad *sinkpad,*srcpad; + + int sock; + struct sockaddr_in theiraddr; + + gint port; + gchar *host; +}; + +struct _GstUDPSinkClass { + GstElementClass parent_class; + +}; + +GType gst_udpsink_get_type(void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_UDPSINK_H__ */ diff --git a/gst/udp/gstudpsrc.c b/gst/udp/gstudpsrc.c new file mode 100644 index 0000000..4400a06 --- /dev/null +++ b/gst/udp/gstudpsrc.c @@ -0,0 +1,300 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + + +#include "gstudpsrc.h" + +#define UDP_DEFAULT_PORT 4951 + +/* elementfactory information */ +GstElementDetails gst_udpsrc_details = { + "UDP packet receiver", + "Transport/", + "", + VERSION, + "Wim Taymans ", + "(C) 2001", +}; + +/* UDPSrc signals and args */ +enum { + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0, + ARG_PORT, + /* FILL ME */ +}; + +static void gst_udpsrc_class_init (GstUDPSrc *klass); +static void gst_udpsrc_init (GstUDPSrc *udpsrc); + +static GstBuffer* gst_udpsrc_get (GstPad *pad); +static GstElementStateReturn + gst_udpsrc_change_state (GstElement *element); + +static void gst_udpsrc_set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec); +static void gst_udpsrc_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec); + +static GstElementClass *parent_class = NULL; +//static guint gst_udpsrc_signals[LAST_SIGNAL] = { 0 }; + +GType +gst_udpsrc_get_type (void) +{ + static GType udpsrc_type = 0; + + + if (!udpsrc_type) { + static const GTypeInfo udpsrc_info = { + sizeof(GstUDPSrcClass), + NULL, + NULL, + (GClassInitFunc)gst_udpsrc_class_init, + NULL, + NULL, + sizeof(GstUDPSrc), + 0, + (GInstanceInitFunc)gst_udpsrc_init, + NULL + }; + udpsrc_type = g_type_register_static (GST_TYPE_ELEMENT, "GstUDPSrc", &udpsrc_info, 0); + } + return udpsrc_type; +} + +static void +gst_udpsrc_class_init (GstUDPSrc *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_PORT, + g_param_spec_int ("port", "port", "The port to receive the packets from", + 0, 32768, UDP_DEFAULT_PORT, G_PARAM_READWRITE)); + + gobject_class->set_property = gst_udpsrc_set_property; + gobject_class->get_property = gst_udpsrc_get_property; + + gstelement_class->change_state = gst_udpsrc_change_state; +} + + +static void +gst_udpsrc_init (GstUDPSrc *udpsrc) +{ + /* create the src and src pads */ + udpsrc->srcpad = gst_pad_new ("src", GST_PAD_SRC); + gst_element_add_pad (GST_ELEMENT (udpsrc), udpsrc->srcpad); + gst_pad_set_get_function (udpsrc->srcpad, gst_udpsrc_get); + + udpsrc->port = UDP_DEFAULT_PORT; +} + +static GstBuffer* +gst_udpsrc_get (GstPad *pad) +{ + GstUDPSrc *udpsrc; + GstBuffer *outbuf; + struct sockaddr_in tmpaddr; + int len, numbytes; + fd_set read_fds; + + g_return_val_if_fail (pad != NULL, NULL); + g_return_val_if_fail (GST_IS_PAD (pad), NULL); + + udpsrc = GST_UDPSRC (GST_OBJECT_PARENT (pad)); + + FD_ZERO (&read_fds); + FD_SET (udpsrc->control_sock, &read_fds); + FD_SET (udpsrc->sock, &read_fds); + + if (select (udpsrc->control_sock+1, &read_fds, NULL, NULL, NULL) > 0) { + if (FD_ISSET (udpsrc->control_sock, &read_fds)) { +#ifndef GST_DISABLE_LOADSAVE + guchar *buf; + int ret; + int fdread; + struct sockaddr addr; + socklen_t len; + xmlDocPtr doc; + GstCaps *caps; + + buf = g_malloc (1024*10); + + len = sizeof (struct sockaddr); + fdread = accept (udpsrc->control_sock, &addr, &len); + if (fdread < 0) { + perror ("accept"); + } + + ret = read (fdread, buf, 1024*10); + if (ret < 0) { + perror ("read"); + } + buf[ret] = '\0'; + doc = xmlParseMemory(buf, ret); + caps = gst_caps_load_thyself(doc->xmlRootNode); + + gst_pad_set_caps (udpsrc->srcpad, caps); + +#endif + outbuf = NULL; + } + else { + outbuf = gst_buffer_new (); + GST_BUFFER_DATA (outbuf) = g_malloc (24000); + GST_BUFFER_SIZE (outbuf) = 24000; + + numbytes = recvfrom (udpsrc->sock, GST_BUFFER_DATA (outbuf), + GST_BUFFER_SIZE (outbuf), 0, (struct sockaddr *)&tmpaddr, &len); + + if (numbytes != -1) { + GST_BUFFER_SIZE (outbuf) = numbytes; + } + else { + perror ("recvfrom"); + gst_buffer_unref (outbuf); + outbuf = NULL; + } + + } + } + else { + perror ("select"); + outbuf = NULL; + } + return outbuf; +} + + +static void +gst_udpsrc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstUDPSrc *udpsrc; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_UDPSRC(object)); + udpsrc = GST_UDPSRC(object); + + switch (prop_id) { + case ARG_PORT: + udpsrc->port = g_value_get_int (value); + break; + default: + break; + } +} + +static void +gst_udpsrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstUDPSrc *udpsrc; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_UDPSRC(object)); + udpsrc = GST_UDPSRC(object); + + switch (prop_id) { + case ARG_PORT: + g_value_set_int (value, udpsrc->port); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +// create a socket for sending to remote machine +static gboolean +gst_udpsrc_init_receive (GstUDPSrc *src) +{ + bzero (&src->myaddr, sizeof (src->myaddr)); + src->myaddr.sin_family = AF_INET; // host byte order + src->myaddr.sin_port = htons (src->port); // short, network byte order + src->myaddr.sin_addr.s_addr = INADDR_ANY; + + if ((src->sock = socket (AF_INET, SOCK_DGRAM, 0)) == -1) { + perror("socket"); + return FALSE; + } + + if (bind (src->sock, (struct sockaddr *) &src->myaddr, sizeof (src->myaddr)) == -1) { + perror("bind"); + return FALSE; + } + + if ((src->control_sock = socket (AF_INET, SOCK_STREAM, 0)) == -1) { + perror("control_socket"); + return FALSE; + } + + if (bind (src->control_sock, (struct sockaddr *) &src->myaddr, sizeof (src->myaddr)) == -1) { + perror("control_bind"); + return FALSE; + } + if (listen (src->control_sock, 5) == -1) { + perror("listen"); + return FALSE; + } + fcntl (src->control_sock, F_SETFL, O_NONBLOCK); + + GST_FLAG_SET (src, GST_UDPSRC_OPEN); + + return TRUE; +} + +static void +gst_udpsrc_close (GstUDPSrc *src) +{ + close (src->sock); + + GST_FLAG_UNSET (src, GST_UDPSRC_OPEN); +} + +static GstElementStateReturn +gst_udpsrc_change_state (GstElement *element) +{ + g_return_val_if_fail (GST_IS_UDPSRC (element), GST_STATE_FAILURE); + + if (GST_STATE_PENDING (element) == GST_STATE_NULL) { + if (GST_FLAG_IS_SET (element, GST_UDPSRC_OPEN)) + gst_udpsrc_close (GST_UDPSRC (element)); + } else { + if (!GST_FLAG_IS_SET (element, GST_UDPSRC_OPEN)) { + if (!gst_udpsrc_init_receive (GST_UDPSRC (element))) + return GST_STATE_FAILURE; + } + } + + if (GST_ELEMENT_CLASS (parent_class)->change_state) + return GST_ELEMENT_CLASS (parent_class)->change_state (element); + + return GST_STATE_SUCCESS; +} + diff --git a/gst/udp/gstudpsrc.h b/gst/udp/gstudpsrc.h new file mode 100644 index 0000000..cf0d1d3 --- /dev/null +++ b/gst/udp/gstudpsrc.h @@ -0,0 +1,88 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + + +#ifndef __GST_UDPSRC_H__ +#define __GST_UDPSRC_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GST_TYPE_UDPSRC \ + (gst_udpsrc_get_type()) +#define GST_UDPSRC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_UDPSRC,GstUDPSrc)) +#define GST_UDPSRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_UDPSRC,GstUDPSrc)) +#define GST_IS_UDPSRC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_UDPSRC)) +#define GST_IS_UDPSRC_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_UDPSRC)) + +typedef struct _GstUDPSrc GstUDPSrc; +typedef struct _GstUDPSrcClass GstUDPSrcClass; + +typedef enum { + GST_UDPSRC_OPEN = GST_ELEMENT_FLAG_LAST, + + GST_UDPSRC_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 2, +} GstUDPSrcFlags; + +struct _GstUDPSrc { + GstElement element; + + /* pads */ + GstPad *sinkpad,*srcpad; + + int port; + int sock; + int control_sock; + struct sockaddr_in myaddr; +}; + +struct _GstUDPSrcClass { + GstElementClass parent_class; +}; + +GType gst_udpsrc_get_type(void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_UDPSRC_H__ */ diff --git a/gst/wavparse/.gitignore b/gst/wavparse/.gitignore new file mode 100644 index 0000000..08f5ed3 --- /dev/null +++ b/gst/wavparse/.gitignore @@ -0,0 +1,7 @@ +Makefile +Makefile.in +*.o +*.lo +*.la +.deps +.libs diff --git a/gst/wavparse/Makefile.am b/gst/wavparse/Makefile.am new file mode 100644 index 0000000..d9c8e4d --- /dev/null +++ b/gst/wavparse/Makefile.am @@ -0,0 +1,8 @@ +filterdir = $(libdir)/gst + +filter_LTLIBRARIES = libgstwavparse.la + +libgstwavparse_la_SOURCES = gstwavparse.c gstriff.c +libgstwavparse_la_CFLAGS = $(GST_CFLAGS) + +noinst_HEADERS = gstwavparse.h gstriff.h diff --git a/gst/wavparse/gstriff.c b/gst/wavparse/gstriff.c new file mode 100644 index 0000000..d343568 --- /dev/null +++ b/gst/wavparse/gstriff.c @@ -0,0 +1,144 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + + +#include +#include + + +GstRiff *gst_riff_new() { + GstRiff *riff; + + riff = (GstRiff *)malloc(sizeof(GstRiff)); + g_return_val_if_fail(riff != NULL, NULL); + + riff->form = 0; + riff->chunks = NULL; + riff->state = 0; + riff->curoffset = 0; + riff->nextlikely = 0; + + return riff; +} + +gint gst_riff_next_buffer(GstRiff *riff,GstBuffer *buf,gulong off) { + gulong last; + GstRiffChunk *chunk; + + g_return_val_if_fail(riff != NULL, 0); + g_return_val_if_fail(buf != NULL, 0); + g_return_val_if_fail(GST_BUFFER_DATA(buf) != NULL, 0); + + last = off + GST_BUFFER_SIZE(buf); + + if (off == 0) { + gulong *words = (gulong *)GST_BUFFER_DATA(buf); + + /* verify this is a valid RIFF file, first of all */ + if (words[0] != gst_riff_fourcc_to_id("RIFF")) { + riff->state = GST_RIFF_ENOTRIFF; + return riff->state; + } + riff->form = words[2]; +// g_print("form is 0x%08x '%s'\n",words[2],gst_riff_id_to_fourcc(words[2])); + riff->nextlikely = 12; /* skip 'RIFF', length, and form */ + } + + /* loop while the next likely chunk header is in this buffer */ + while ((riff->nextlikely+8) < last) { + gulong *words = (gulong *)((guchar *)GST_BUFFER_DATA(buf) + riff->nextlikely); + +// g_print("next likely chunk is at offset 0x%08x\n",riff->nextlikely); + chunk = (GstRiffChunk *)malloc(sizeof(GstRiffChunk)); + g_return_val_if_fail(chunk != NULL,0); + chunk->offset = riff->nextlikely+8; /* point to the actual data */ + chunk->id = words[0]; + chunk->size = words[1]; +// g_print("chunk id is 0x%08x '%s' and is 0x%08x long\n",words[0], +// gst_riff_id_to_fourcc(words[0]),words[1]); + riff->nextlikely += 8 + chunk->size; /* doesn't include hdr */ + riff->chunks = g_list_prepend(riff->chunks,chunk); + } + + return 0; +} + + +gulong gst_riff_fourcc_to_id(gchar *fourcc) { + g_return_val_if_fail(fourcc != NULL,0); + + return (fourcc[0] << 0) | (fourcc[1] << 8) | + (fourcc[2] << 16) | (fourcc[3] << 24); +} + +gchar *gst_riff_id_to_fourcc(gulong id) { + gchar *fourcc = (gchar *)malloc(5); + + g_return_val_if_fail(fourcc != NULL, NULL); + + fourcc[0] = (id >> 0) & 0xff; + fourcc[1] = (id >> 8) & 0xff; + fourcc[2] = (id >> 16) & 0xff; + fourcc[3] = (id >> 24) & 0xff; + fourcc[4] = 0; + + return fourcc; +} + +GList *gst_riff_get_chunk_list(GstRiff *riff) { + g_return_val_if_fail(riff != NULL, NULL); + + return riff->chunks; +} + +GstRiffChunk *gst_riff_get_chunk(GstRiff *riff,gchar *fourcc) { + GList *chunk; + + g_return_val_if_fail(riff != NULL, NULL); + g_return_val_if_fail(fourcc != NULL, NULL); + + chunk = riff->chunks; + while (chunk) { + if (((GstRiffChunk *)(chunk->data))->id == gst_riff_fourcc_to_id(fourcc)) + return (GstRiffChunk *)(chunk->data); + chunk = g_list_next(chunk); + } + + return NULL; +} + +gulong gst_riff_get_nextlikely(GstRiff *riff) { + g_return_val_if_fail(riff != NULL, 0); + + return riff->nextlikely; +} + +/* + guchar *hchar = (guchar *)(buf->data); + gulong hlong = *(gulong *)(buf->data); + + g_print("header is 0x%08x native, %02x %02x %02x %02x, '%c%c%c%c'\n", + hlong, + hchar[0],hchar[1],hchar[2],hchar[3], + hchar[0],hchar[1],hchar[2],hchar[3]); + g_print("header 0x%08x translates to '%s'\n",hlong, + gst_riff_id_to_fourcc(hlong)); + g_print("header 0x%08x trancodes to 0x%08x\n",hlong, + gst_riff_fourcc_to_id(gst_riff_id_to_fourcc(hlong))); +*/ diff --git a/gst/wavparse/gstriff.h b/gst/wavparse/gstriff.h new file mode 100644 index 0000000..de959fd --- /dev/null +++ b/gst/wavparse/gstriff.h @@ -0,0 +1,67 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + + +#ifndef __GST_RIFF_H__ +#define __GST_RIFF_H__ + + +#include +#include + + +#define GST_RIFF_ENOTRIFF -1 /* not a RIFF file */ + + +typedef struct _GstRiff GstRiff; +typedef struct _GstRiffChunk GstRiffChunk; + +struct _GstRiff { + guint32 form; + + /* list of chunks, most recent at the head */ + GList *chunks; + + /* parse state */ + gint state; + guint32 curoffset; + guint32 nextlikely; +}; + +struct _GstRiffChunk { + gulong offset; + + guint32 id; + guint32 size; +}; + + +GstRiff *gst_riff_new(); +gint gst_riff_next_buffer(GstRiff *riff,GstBuffer *buf,gulong off); +GList *gst_riff_get_chunk_list(GstRiff *riff); +GstRiffChunk *gst_riff_get_chunk(GstRiff *riff,gchar *fourcc); +GstRiffChunk *gst_riff_get_chunk_number(GstRiff *riff,gint number); + +gulong gst_riff_get_nextlikely(GstRiff *riff); + +gulong gst_riff_fourcc_to_id(gchar *fourcc); +gchar *gst_riff_id_to_fourcc(gulong id); + + +#endif /* __GST_RIFF_H__ */ diff --git a/gst/wavparse/gstwavparse.c b/gst/wavparse/gstwavparse.c new file mode 100644 index 0000000..2e57da8 --- /dev/null +++ b/gst/wavparse/gstwavparse.c @@ -0,0 +1,367 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + + +#include + +#include + +static void gst_parsewav_class_init (GstParseWavClass *klass); +static void gst_parsewav_init (GstParseWav *parsewav); + +static GstCaps* wav_typefind (GstBuffer *buf, gpointer private); + +static void gst_parsewav_chain (GstPad *pad, GstBuffer *buf); + +/* elementfactory information */ +static GstElementDetails gst_parsewav_details = { + ".wav parser", + "Parser/Audio", + "Parse a .wav file into raw audio", + VERSION, + "Erik Walthinsen ", + "(C) 1999", +}; + +GST_PADTEMPLATE_FACTORY (sink_template_factory, + "parsewav_sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "parsewav_wav", + "audio/wav", + NULL + ) +) + +GST_PADTEMPLATE_FACTORY (src_template_factory, + "parsewav_src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "parsewav_raw", + "audio/raw", + "format", GST_PROPS_STRING ("int"), + "law", GST_PROPS_INT (0), + "endianness", GST_PROPS_INT (G_BYTE_ORDER), + "signed", GST_PROPS_BOOLEAN (TRUE), + "width", GST_PROPS_LIST ( + GST_PROPS_INT (8), + GST_PROPS_INT (16) + ), + "depth", GST_PROPS_LIST ( + GST_PROPS_INT (8), + GST_PROPS_INT (16) + ), + "rate", GST_PROPS_INT_RANGE (8000, 48000), + "channels", GST_PROPS_INT_RANGE (1, 2) + ) +) + +/* typefactory for 'wav' */ +static GstTypeDefinition +wavdefinition = +{ + "parsewav_audio/wav", + "audio/wav", + ".wav", + wav_typefind, +}; + + +/* ParseWav signals and args */ +enum { + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0, + /* FILL ME */ +}; + +static GstElementClass *parent_class = NULL; +//static guint gst_parsewav_signals[LAST_SIGNAL] = { 0 }; + +GType +gst_parsewav_get_type (void) +{ + static GType parsewav_type = 0; + + if (!parsewav_type) { + static const GTypeInfo parsewav_info = { + sizeof(GstParseWavClass), NULL, + NULL, + (GClassInitFunc) gst_parsewav_class_init, + NULL, + NULL, + sizeof(GstParseWav), + 0, + (GInstanceInitFunc) gst_parsewav_init, + }; + parsewav_type = g_type_register_static (GST_TYPE_ELEMENT, "GstParseWav", &parsewav_info, 0); + } + return parsewav_type; +} + +static void +gst_parsewav_class_init (GstParseWavClass *klass) +{ + GstElementClass *gstelement_class; + + gstelement_class = (GstElementClass*) klass; + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); +} + +static void +gst_parsewav_init (GstParseWav *parsewav) +{ + parsewav->sinkpad = gst_pad_new_from_template (GST_PADTEMPLATE_GET (sink_template_factory), "sink"); + gst_element_add_pad (GST_ELEMENT (parsewav), parsewav->sinkpad); + gst_pad_set_chain_function (parsewav->sinkpad, gst_parsewav_chain); + + parsewav->srcpad = gst_pad_new_from_template (GST_PADTEMPLATE_GET (src_template_factory), "src"); + gst_element_add_pad (GST_ELEMENT (parsewav), parsewav->srcpad); + + parsewav->riff = NULL; + + parsewav->state = GST_PARSEWAV_UNKNOWN; + parsewav->riff = NULL; + parsewav->riff_nextlikely = 0; + parsewav->size = 0; + parsewav->bps = 0; +} + +static GstCaps* +wav_typefind (GstBuffer *buf, gpointer private) +{ + gchar *data = GST_BUFFER_DATA (buf); + + if (strncmp (&data[0], "RIFF", 4)) return NULL; + if (strncmp (&data[8], "WAVE", 4)) return NULL; + + return gst_caps_new ("wav_typefind", "audio/wav", NULL); +} + + +static void +gst_parsewav_chain (GstPad *pad, GstBuffer *buf) +{ + GstParseWav *parsewav; + gboolean buffer_riffed = FALSE; /* so we don't parse twice */ + gchar *data; + gulong size; + + g_return_if_fail (pad != NULL); + g_return_if_fail (GST_IS_PAD (pad)); + g_return_if_fail (buf != NULL); + g_return_if_fail (GST_BUFFER_DATA (buf) != NULL); + + parsewav = GST_PARSEWAV (gst_pad_get_parent (pad)); + GST_DEBUG (0, "gst_parsewav_chain: got buffer in '%s'\n", + gst_object_get_name (GST_OBJECT (parsewav))); + data = (guchar *) GST_BUFFER_DATA (buf); + size = GST_BUFFER_SIZE (buf); + + /* walk through the states in priority order */ + /* we're in the data region */ + if (parsewav->state == GST_PARSEWAV_DATA) { + /* if we're expected to see a new chunk in this buffer */ + if ((parsewav->riff_nextlikely - GST_BUFFER_OFFSET (buf)) < GST_BUFFER_SIZE (buf)) { + + GST_BUFFER_SIZE (buf) = parsewav->riff_nextlikely - GST_BUFFER_OFFSET (buf); + + parsewav->state = GST_PARSEWAV_OTHER; + /* I suppose we could signal an EOF at this point, but that may be + premature. We've stopped data flow, that's the main thing. */ + } + gst_pad_push (parsewav->srcpad, buf); + return; + } + + if (parsewav->state == GST_PARSEWAV_OTHER) { + GST_DEBUG (0, "we're in unknown territory here, not passing on\n"); + return; + } + + + /* here we deal with parsing out the primary state */ + /* these are sequenced such that in the normal case each (RIFF/WAVE, + fmt, data) will fire in sequence, as they should */ + + /* we're in null state now, look for the RIFF header, start parsing */ + if (parsewav->state == GST_PARSEWAV_UNKNOWN) { + gint retval; + + GST_DEBUG (0, "GstParseWav: checking for RIFF format\n"); + + /* create a new RIFF parser */ + parsewav->riff = gst_riff_new (); + + /* give it the current buffer to start parsing */ + retval = gst_riff_next_buffer (parsewav->riff, buf, 0); + buffer_riffed = TRUE; + if (retval < 0) { + GST_DEBUG (0, "sorry, isn't RIFF\n"); + return; + } + + /* this has to be a file of form WAVE for us to deal with it */ + if (parsewav->riff->form != gst_riff_fourcc_to_id ("WAVE")) { + GST_DEBUG (0, "sorry, isn't WAVE\n"); + return; + } + + /* at this point we're waiting for the 'fmt ' chunk */ + parsewav->state = GST_PARSEWAV_CHUNK_FMT; + } + + /* we're now looking for the 'fmt ' chunk to get the audio info */ + if (parsewav->state == GST_PARSEWAV_CHUNK_FMT) { + GstRiffChunk *fmt; + GstParseWavFormat *format; + + GST_DEBUG (0, "GstParseWav: looking for fmt chunk\n"); + + /* there's a good possibility we may not have parsed this buffer */ + if (buffer_riffed == FALSE) { + gst_riff_next_buffer (parsewav->riff, buf, GST_BUFFER_OFFSET (buf)); + buffer_riffed = TRUE; + } + + /* see if the fmt chunk is available yet */ + fmt = gst_riff_get_chunk (parsewav->riff, "fmt "); + + /* if we've got something, deal with it */ + if (fmt != NULL) { + + /* we can gather format information now */ + format = (GstParseWavFormat *)((guchar *) GST_BUFFER_DATA (buf) + fmt->offset); + + /* set the caps on the src pad */ + gst_pad_set_caps (parsewav->srcpad, gst_caps_new ( + "parsewav_src", + "audio/raw", + gst_props_new ( + "format", GST_PROPS_STRING ("int"), + "law", GST_PROPS_INT (0), //FIXME + "endianness", GST_PROPS_INT (G_BYTE_ORDER), + "signed", GST_PROPS_BOOLEAN (TRUE), //FIXME + "width", GST_PROPS_INT (format->wBitsPerSample), + "depth", GST_PROPS_INT (format->wBitsPerSample), + "rate", GST_PROPS_INT (format->dwSamplesPerSec), + "channels", GST_PROPS_INT (format->wChannels), + NULL + ) + )); + + parsewav->bps = format->wBlockAlign; + GST_DEBUG (0, "frequency %d, channels %d\n", + format->dwSamplesPerSec, format->wChannels); + + /* we're now looking for the data chunk */ + parsewav->state = GST_PARSEWAV_CHUNK_DATA; + } else { + /* otherwise we just sort of give up for this buffer */ + gst_buffer_unref (buf); + return; + } + } + + /* now we look for the data chunk */ + if (parsewav->state == GST_PARSEWAV_CHUNK_DATA) { + GstBuffer *newbuf; + GstRiffChunk *datachunk; + + GST_DEBUG (0, "GstParseWav: looking for data chunk\n"); + + /* again, we might need to parse the buffer */ + if (buffer_riffed == FALSE) { + gst_riff_next_buffer (parsewav->riff, buf, GST_BUFFER_OFFSET (buf)); + buffer_riffed = TRUE; + } + + datachunk = gst_riff_get_chunk (parsewav->riff, "data"); + + if (datachunk != NULL) { + gulong subsize; + + GST_DEBUG (0, "data begins at %ld\n", datachunk->offset); + + /* at this point we can ACK that we have data */ + parsewav->state = GST_PARSEWAV_DATA; + + /* now we construct a new buffer for the remainder */ + subsize = size - datachunk->offset; + GST_DEBUG (0, "sending last %ld bytes along as audio\n", subsize); + + newbuf = gst_buffer_new (); + GST_BUFFER_DATA (newbuf) = g_malloc (subsize); + GST_BUFFER_SIZE (newbuf) = subsize; + + memcpy (GST_BUFFER_DATA (newbuf), GST_BUFFER_DATA (buf) + datachunk->offset, subsize); + + gst_buffer_unref (buf); + + gst_pad_push (parsewav->srcpad, newbuf); + + /* now we're ready to go, the next buffer should start data */ + parsewav->state = GST_PARSEWAV_DATA; + + /* however, we may be expecting another chunk at some point */ + parsewav->riff_nextlikely = gst_riff_get_nextlikely (parsewav->riff); + } else { + /* otherwise we just sort of give up for this buffer */ + gst_buffer_unref (buf); + return; + } + } +} + + +static gboolean +plugin_init (GModule *module, GstPlugin *plugin) +{ + GstElementFactory *factory; + GstTypeFactory *type; + + /* create an elementfactory for the parsewav element */ + factory = gst_elementfactory_new ("parsewav", GST_TYPE_PARSEWAV, + &gst_parsewav_details); + g_return_val_if_fail(factory != NULL, FALSE); + + /* register src pads */ + gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (sink_template_factory)); + gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (src_template_factory)); + + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); + + type = gst_typefactory_new (&wavdefinition); + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (type)); + + return TRUE; +} + +GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "parsewav", + plugin_init +}; diff --git a/gst/wavparse/gstwavparse.h b/gst/wavparse/gstwavparse.h new file mode 100644 index 0000000..55cb491 --- /dev/null +++ b/gst/wavparse/gstwavparse.h @@ -0,0 +1,99 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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. + */ + + +#ifndef __GST_PARSEWAV_H__ +#define __GST_PARSEWAV_H__ + + +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GST_TYPE_PARSEWAV \ + (gst_parsewav_get_type()) +#define GST_PARSEWAV(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PARSEWAV,GstParseWav)) +#define GST_PARSEWAV_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PARSEWAV,GstParseWav)) +#define GST_IS_PARSEWAV(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PARSEWAV)) +#define GST_IS_PARSEWAV_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PARSEWAV)) + + +#define GST_PARSEWAV_UNKNOWN 0 /* initialized state */ +#define GST_PARSEWAV_CHUNK_FMT 1 /* searching for fmt */ +#define GST_PARSEWAV_CHUNK_DATA 2 /* searching for data */ +#define GST_PARSEWAV_DATA 3 /* in data region */ +#define GST_PARSEWAV_OTHER 4 /* in unknown region */ + +typedef struct _GstParseWav GstParseWav; +typedef struct _GstParseWavClass GstParseWavClass; + +struct _GstParseWav { + GstElement element; + + /* pads */ + GstPad *sinkpad,*srcpad; + + /* WAVE decoding state */ + gint state; + + /* RIFF decoding state */ + GstRiff *riff; + gulong riff_nextlikely; + + /* expected length of audio */ + gulong size; + + /* useful audio data */ + gint bps; + +}; + +struct _GstParseWavClass { + GstElementClass parent_class; +}; + +GType gst_parsewav_get_type(void); + +typedef struct _GstParseWavFormat GstParseWavFormat; + +struct _GstParseWavFormat { + gint16 wFormatTag; + guint16 wChannels; + guint32 dwSamplesPerSec; + guint32 dwAvgBytesPerSec; + guint16 wBlockAlign; + guint16 wBitsPerSample; +}; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_PARSEAU_H__ */ -- 2.7.4