2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
23 #include <gstwavparse.h>
25 static void gst_wavparse_class_init (GstWavParseClass *klass);
26 static void gst_wavparse_init (GstWavParse *wavparse);
28 static GstCaps* wav_typefind (GstBuffer *buf, gpointer private);
30 static void gst_wavparse_chain (GstPad *pad, GstBuffer *buf);
32 /* elementfactory information */
33 static GstElementDetails gst_wavparse_details = {
36 "Parse a .wav file into raw audio",
38 "Erik Walthinsen <omega@cse.ogi.edu>",
42 GST_PADTEMPLATE_FACTORY (sink_template_factory,
53 GST_PADTEMPLATE_FACTORY (src_template_factory,
60 "format", GST_PROPS_STRING ("int"),
61 "law", GST_PROPS_INT (0),
62 "endianness", GST_PROPS_INT (G_BYTE_ORDER),
63 "signed", GST_PROPS_BOOLEAN (TRUE),
64 "width", GST_PROPS_LIST (
68 "depth", GST_PROPS_LIST (
72 "rate", GST_PROPS_INT_RANGE (8000, 48000),
73 "channels", GST_PROPS_INT_RANGE (1, 2)
77 /* typefactory for 'wav' */
78 static GstTypeDefinition
88 /* WavParse signals and args */
99 static GstElementClass *parent_class = NULL;
100 /*static guint gst_wavparse_signals[LAST_SIGNAL] = { 0 }; */
103 gst_wavparse_get_type (void)
105 static GType wavparse_type = 0;
107 if (!wavparse_type) {
108 static const GTypeInfo wavparse_info = {
109 sizeof(GstWavParseClass), NULL,
111 (GClassInitFunc) gst_wavparse_class_init,
116 (GInstanceInitFunc) gst_wavparse_init,
118 wavparse_type = g_type_register_static (GST_TYPE_ELEMENT, "GstWavParse", &wavparse_info, 0);
120 return wavparse_type;
124 gst_wavparse_class_init (GstWavParseClass *klass)
126 GstElementClass *gstelement_class;
128 gstelement_class = (GstElementClass*) klass;
130 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
134 gst_wavparse_init (GstWavParse *wavparse)
136 wavparse->sinkpad = gst_pad_new_from_template (GST_PADTEMPLATE_GET (sink_template_factory), "sink");
137 gst_element_add_pad (GST_ELEMENT (wavparse), wavparse->sinkpad);
138 gst_pad_set_chain_function (wavparse->sinkpad, gst_wavparse_chain);
140 wavparse->srcpad = gst_pad_new_from_template (GST_PADTEMPLATE_GET (src_template_factory), "src");
141 gst_element_add_pad (GST_ELEMENT (wavparse), wavparse->srcpad);
143 wavparse->riff = NULL;
145 wavparse->state = GST_WAVPARSE_UNKNOWN;
146 wavparse->riff = NULL;
147 wavparse->riff_nextlikely = 0;
153 wav_typefind (GstBuffer *buf, gpointer private)
155 gchar *data = GST_BUFFER_DATA (buf);
157 if (strncmp (&data[0], "RIFF", 4)) return NULL;
158 if (strncmp (&data[8], "WAVE", 4)) return NULL;
160 return gst_caps_new ("wav_typefind", "audio/wav", NULL);
165 gst_wavparse_chain (GstPad *pad, GstBuffer *buf)
167 GstWavParse *wavparse;
168 gboolean buffer_riffed = FALSE; /* so we don't parse twice */
172 g_return_if_fail (pad != NULL);
173 g_return_if_fail (GST_IS_PAD (pad));
174 g_return_if_fail (buf != NULL);
175 g_return_if_fail (GST_BUFFER_DATA (buf) != NULL);
177 wavparse = GST_WAVPARSE (gst_pad_get_parent (pad));
178 GST_DEBUG (0, "gst_wavparse_chain: got buffer in '%s'\n",
179 gst_object_get_name (GST_OBJECT (wavparse)));
180 data = (guchar *) GST_BUFFER_DATA (buf);
181 size = GST_BUFFER_SIZE (buf);
183 /* walk through the states in priority order */
184 /* we're in the data region */
185 if (wavparse->state == GST_WAVPARSE_DATA) {
186 /* if we're expected to see a new chunk in this buffer */
187 if ((wavparse->riff_nextlikely - GST_BUFFER_OFFSET (buf)) < GST_BUFFER_SIZE (buf)) {
189 GST_BUFFER_SIZE (buf) = wavparse->riff_nextlikely - GST_BUFFER_OFFSET (buf);
191 wavparse->state = GST_WAVPARSE_OTHER;
192 /* I suppose we could signal an EOF at this point, but that may be
193 premature. We've stopped data flow, that's the main thing. */
195 gst_pad_push (wavparse->srcpad, buf);
199 if (wavparse->state == GST_WAVPARSE_OTHER) {
200 GST_DEBUG (0, "we're in unknown territory here, not passing on\n");
205 /* here we deal with parsing out the primary state */
206 /* these are sequenced such that in the normal case each (RIFF/WAVE,
207 fmt, data) will fire in sequence, as they should */
209 /* we're in null state now, look for the RIFF header, start parsing */
210 if (wavparse->state == GST_WAVPARSE_UNKNOWN) {
213 GST_DEBUG (0, "GstWavParse: checking for RIFF format\n");
215 /* create a new RIFF parser */
216 wavparse->riff = gst_riff_new ();
218 /* give it the current buffer to start parsing */
219 retval = gst_riff_next_buffer (wavparse->riff, buf, 0);
220 buffer_riffed = TRUE;
222 GST_DEBUG (0, "sorry, isn't RIFF\n");
226 /* this has to be a file of form WAVE for us to deal with it */
227 if (wavparse->riff->form != gst_riff_fourcc_to_id ("WAVE")) {
228 GST_DEBUG (0, "sorry, isn't WAVE\n");
232 /* at this point we're waiting for the 'fmt ' chunk */
233 wavparse->state = GST_WAVPARSE_CHUNK_FMT;
236 /* we're now looking for the 'fmt ' chunk to get the audio info */
237 if (wavparse->state == GST_WAVPARSE_CHUNK_FMT) {
239 GstWavParseFormat *format;
241 GST_DEBUG (0, "GstWavParse: looking for fmt chunk\n");
243 /* there's a good possibility we may not have parsed this buffer */
244 if (buffer_riffed == FALSE) {
245 gst_riff_next_buffer (wavparse->riff, buf, GST_BUFFER_OFFSET (buf));
246 buffer_riffed = TRUE;
249 /* see if the fmt chunk is available yet */
250 fmt = gst_riff_get_chunk (wavparse->riff, "fmt ");
252 /* if we've got something, deal with it */
257 /* we can gather format information now */
258 format = (GstWavParseFormat *)((guchar *) GST_BUFFER_DATA (buf) + fmt->offset);
260 /* set the caps on the src pad */
261 caps = GST_CAPS_NEW (
264 "format", GST_PROPS_STRING ("int"),
265 "law", GST_PROPS_INT (0), /*FIXME */
266 "endianness", GST_PROPS_INT (G_BYTE_ORDER),
267 "signed", GST_PROPS_BOOLEAN (TRUE), /*FIXME */
268 "width", GST_PROPS_INT (format->wBitsPerSample),
269 "depth", GST_PROPS_INT (format->wBitsPerSample),
270 "rate", GST_PROPS_INT (format->dwSamplesPerSec),
271 "channels", GST_PROPS_INT (format->wChannels)
274 gst_pad_try_set_caps (wavparse->srcpad, caps);
276 wavparse->bps = format->wBlockAlign;
277 GST_DEBUG (0, "frequency %d, channels %d\n",
278 format->dwSamplesPerSec, format->wChannels);
280 /* we're now looking for the data chunk */
281 wavparse->state = GST_WAVPARSE_CHUNK_DATA;
283 /* otherwise we just sort of give up for this buffer */
284 gst_buffer_unref (buf);
289 /* now we look for the data chunk */
290 if (wavparse->state == GST_WAVPARSE_CHUNK_DATA) {
292 GstRiffChunk *datachunk;
294 GST_DEBUG (0, "GstWavParse: looking for data chunk\n");
296 /* again, we might need to parse the buffer */
297 if (buffer_riffed == FALSE) {
298 gst_riff_next_buffer (wavparse->riff, buf, GST_BUFFER_OFFSET (buf));
299 buffer_riffed = TRUE;
302 datachunk = gst_riff_get_chunk (wavparse->riff, "data");
304 if (datachunk != NULL) {
307 GST_DEBUG (0, "data begins at %ld\n", datachunk->offset);
309 /* at this point we can ACK that we have data */
310 wavparse->state = GST_WAVPARSE_DATA;
312 /* now we construct a new buffer for the remainder */
313 subsize = size - datachunk->offset;
314 GST_DEBUG (0, "sending last %ld bytes along as audio\n", subsize);
316 newbuf = gst_buffer_new ();
317 GST_BUFFER_DATA (newbuf) = g_malloc (subsize);
318 GST_BUFFER_SIZE (newbuf) = subsize;
320 memcpy (GST_BUFFER_DATA (newbuf), GST_BUFFER_DATA (buf) + datachunk->offset, subsize);
322 gst_buffer_unref (buf);
324 gst_pad_push (wavparse->srcpad, newbuf);
326 /* now we're ready to go, the next buffer should start data */
327 wavparse->state = GST_WAVPARSE_DATA;
329 /* however, we may be expecting another chunk at some point */
330 wavparse->riff_nextlikely = gst_riff_get_nextlikely (wavparse->riff);
332 /* otherwise we just sort of give up for this buffer */
333 gst_buffer_unref (buf);
341 plugin_init (GModule *module, GstPlugin *plugin)
343 GstElementFactory *factory;
344 GstTypeFactory *type;
346 /* create an elementfactory for the wavparse element */
347 factory = gst_elementfactory_new ("wavparse", GST_TYPE_WAVPARSE,
348 &gst_wavparse_details);
349 g_return_val_if_fail(factory != NULL, FALSE);
351 /* register src pads */
352 gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (sink_template_factory));
353 gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (src_template_factory));
355 gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
357 type = gst_typefactory_new (&wavdefinition);
358 gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (type));
363 GstPluginDesc plugin_desc = {