summaryrefslogtreecommitdiffstats
path: root/gst/wavparse/gstwavparse.c
diff options
context:
space:
mode:
Diffstat (limited to 'gst/wavparse/gstwavparse.c')
-rw-r--r--gst/wavparse/gstwavparse.c367
1 files changed, 367 insertions, 0 deletions
diff --git a/gst/wavparse/gstwavparse.c b/gst/wavparse/gstwavparse.c
new file mode 100644
index 00000000..2e57da83
--- /dev/null
+++ b/gst/wavparse/gstwavparse.c
@@ -0,0 +1,367 @@
+/* Gnome-Streamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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 <string.h>
+
+#include <gstwavparse.h>
+
+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 <omega@cse.ogi.edu>",
+ "(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
+};