change NULL to (NULL) for GST_ELEMENT_ERROR
[platform/upstream/gst-plugins-good.git] / gst / wavparse / gstwavparse.c
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
2 /* GStreamer
3  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include <string.h>
26
27 #include <gstwavparse.h>
28
29 static void             gst_wavparse_base_init          (gpointer g_class);
30 static void             gst_wavparse_class_init         (GstWavParseClass *klass);
31 static void             gst_wavparse_init               (GstWavParse *wavparse);
32
33 static GstElementStateReturn
34                         gst_wavparse_change_state       (GstElement *element);
35
36 static const GstFormat* gst_wavparse_get_formats        (GstPad *pad);
37 static const GstQueryType *
38                         gst_wavparse_get_query_types    (GstPad *pad);
39 static gboolean         gst_wavparse_pad_query          (GstPad *pad, 
40                                                          GstQueryType type,
41                                                          GstFormat *format, 
42                                                          gint64 *value);
43 static gboolean         gst_wavparse_pad_convert        (GstPad *pad,
44                                                          GstFormat src_format,
45                                                          gint64 src_value,
46                                                          GstFormat *dest_format,
47                                                          gint64 *dest_value);
48
49 static void             gst_wavparse_loop               (GstElement *element);
50 static const GstEventMask*
51                         gst_wavparse_get_event_masks    (GstPad *pad);
52 static gboolean         gst_wavparse_srcpad_event       (GstPad *pad, GstEvent *event);
53 static void             gst_wavparse_get_property       (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
54
55 /* elementfactory information */
56 static GstElementDetails gst_wavparse_details = GST_ELEMENT_DETAILS (
57   ".wav demuxer",
58   "Codec/Demuxer",
59   "Parse a .wav file into raw audio",
60   "Erik Walthinsen <omega@cse.ogi.edu>"
61 );
62
63 static GstStaticPadTemplate sink_template_factory =
64 GST_STATIC_PAD_TEMPLATE (
65   "wavparse_sink",
66   GST_PAD_SINK,
67   GST_PAD_ALWAYS,
68   GST_STATIC_CAPS ("audio/x-wav")
69 );
70
71 static GstStaticPadTemplate src_template_factory =
72 GST_STATIC_PAD_TEMPLATE (
73   "wavparse_src",
74   GST_PAD_SRC,
75   GST_PAD_ALWAYS,
76   GST_STATIC_CAPS (
77     "audio/x-raw-int, "
78       "endianness = (int) little_endian, "
79       "signed = (boolean) { true, false }, "
80       "width = (int) { 8, 16 }, "
81       "depth = (int) { 8, 16 }, "
82       "rate = (int) [ 8000, 48000 ], "
83       "channels = (int) [ 1, 2 ]; "
84     "audio/mpeg, "
85       "mpegversion = (int) 1, "
86       "layer = (int) [ 1, 3 ], "
87       "rate = (int) [ 8000, 48000 ], "
88       "channels = (int) [ 1, 2 ]; "
89     "audio/x-alaw, "
90       "rate = (int) [ 8000, 48000 ], "
91       "channels = (int) [ 1, 2 ]; "
92     "audio/x-mulaw, "
93       "rate = (int) [ 8000, 48000 ], "
94       "channels = (int) [ 1, 2 ]"
95   )
96 );
97
98 /* WavParse signals and args */
99 enum {
100   /* FILL ME */
101   LAST_SIGNAL
102 };
103
104 enum {
105   PROP_0,
106 };
107
108 static GstElementClass *parent_class = NULL;
109 /*static guint gst_wavparse_signals[LAST_SIGNAL] = { 0 }; */
110
111 GType
112 gst_wavparse_get_type (void) 
113 {
114   static GType wavparse_type = 0;
115
116   if (!wavparse_type) {
117     static const GTypeInfo wavparse_info = {
118       sizeof(GstWavParseClass),
119       gst_wavparse_base_init,
120       NULL,
121       (GClassInitFunc) gst_wavparse_class_init,
122       NULL,
123       NULL,
124       sizeof(GstWavParse),
125       0,
126       (GInstanceInitFunc) gst_wavparse_init,
127     };
128     wavparse_type = g_type_register_static (GST_TYPE_ELEMENT, "GstWavParse", &wavparse_info, 0);
129   }
130   return wavparse_type;
131 }
132
133
134 static void
135 gst_wavparse_base_init (gpointer g_class) 
136 {
137   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
138   
139   gst_element_class_set_details (element_class, &gst_wavparse_details);
140
141   /* register src pads */
142   gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&sink_template_factory));
143   gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&src_template_factory));
144 }
145 static void
146 gst_wavparse_class_init (GstWavParseClass *klass) 
147 {
148   GstElementClass *gstelement_class;
149   GObjectClass *object_class;
150   
151   gstelement_class = (GstElementClass*) klass;
152   object_class = (GObjectClass *) klass;
153   
154   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
155
156   object_class->get_property = gst_wavparse_get_property;
157   gstelement_class->change_state = gst_wavparse_change_state;
158 }
159
160 static void 
161 gst_wavparse_init (GstWavParse *wavparse) 
162 {
163   /* sink */
164   wavparse->sinkpad = gst_pad_new_from_template (gst_static_pad_template_get (&sink_template_factory), "sink");
165   gst_element_add_pad (GST_ELEMENT (wavparse), wavparse->sinkpad);
166
167   gst_pad_set_formats_function (wavparse->sinkpad, gst_wavparse_get_formats);
168   gst_pad_set_convert_function (wavparse->sinkpad, gst_wavparse_pad_convert);
169   gst_pad_set_query_type_function (wavparse->sinkpad, 
170                                    gst_wavparse_get_query_types);
171   gst_pad_set_query_function (wavparse->sinkpad, gst_wavparse_pad_query);
172
173   /* source */
174   wavparse->srcpad = gst_pad_new_from_template (gst_static_pad_template_get (&src_template_factory), "src");
175   gst_pad_use_explicit_caps (wavparse->srcpad);
176   gst_element_add_pad (GST_ELEMENT (wavparse), wavparse->srcpad);
177   gst_pad_set_formats_function (wavparse->srcpad, gst_wavparse_get_formats);
178   gst_pad_set_convert_function (wavparse->srcpad, gst_wavparse_pad_convert);
179   gst_pad_set_query_type_function (wavparse->srcpad,
180                                    gst_wavparse_get_query_types);
181   gst_pad_set_query_function (wavparse->srcpad, gst_wavparse_pad_query);
182   gst_pad_set_event_function (wavparse->srcpad, gst_wavparse_srcpad_event);
183   gst_pad_set_event_mask_function (wavparse->srcpad, gst_wavparse_get_event_masks);
184
185   gst_element_set_loop_function (GST_ELEMENT (wavparse), gst_wavparse_loop);
186
187   wavparse->state = GST_WAVPARSE_UNKNOWN;
188   wavparse->bps = 0;
189   wavparse->seek_pending = FALSE;
190   wavparse->seek_offset = 0;
191 }
192
193 static void
194 gst_wavparse_get_property (GObject *object,
195                            guint prop_id,
196                            GValue *value,
197                            GParamSpec *pspec)
198 {
199   GstWavParse *wavparse;
200
201   wavparse = GST_WAVPARSE (object);
202
203   switch (prop_id) {
204   default:
205     break;
206   }
207 }
208
209 #if 0
210 static void
211 gst_wavparse_parse_adtl (GstWavParse *wavparse,
212                          int len)
213 {
214   guint32 got_bytes;
215   GstByteStream *bs = wavparse->bs;
216   gst_riff_chunk *temp_chunk, chunk;
217   guint8 *tempdata;
218   struct _gst_riff_labl labl, *temp_labl;
219   struct _gst_riff_ltxt ltxt, *temp_ltxt;
220   struct _gst_riff_note note, *temp_note;
221   char *label_name;
222   GstProps *props;
223   GstPropsEntry *entry;
224   GstCaps *new_caps;
225   GList *caps = NULL;
226
227   props = wavparse->metadata->properties;
228   
229   while (len > 0) {
230     got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (gst_riff_chunk));
231     if (got_bytes != sizeof (gst_riff_chunk)) {
232       return;
233     }
234     temp_chunk = (gst_riff_chunk *) tempdata;
235     
236     chunk.id = GUINT32_FROM_LE (temp_chunk->id);
237     chunk.size = GUINT32_FROM_LE (temp_chunk->size);
238
239     if (chunk.size == 0) {
240       gst_bytestream_flush (bs, sizeof (gst_riff_chunk));
241       len -= sizeof (gst_riff_chunk);
242       continue;
243     }
244     
245     switch  (chunk.id) {
246     case GST_RIFF_adtl_labl:
247       got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (struct _gst_riff_labl));
248       if (got_bytes != sizeof (struct _gst_riff_labl)) {
249         return;
250       }
251       
252       temp_labl = (struct _gst_riff_labl *) tempdata;
253       labl.id = GUINT32_FROM_LE (temp_labl->id);
254       labl.size = GUINT32_FROM_LE (temp_labl->size);
255       labl.identifier = GUINT32_FROM_LE (temp_labl->identifier);
256
257       gst_bytestream_flush (bs, sizeof (struct _gst_riff_labl));
258       len -= sizeof (struct _gst_riff_labl);
259       
260       got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, labl.size - 4);
261       if (got_bytes != labl.size - 4) {
262         return;
263       }
264
265       label_name = (char *) tempdata;
266       
267       gst_bytestream_flush (bs, ((labl.size - 4) + 1) & ~1);
268       len -= (( (labl.size - 4) + 1) & ~1);
269
270       new_caps = gst_caps_new ("label",
271                                                                                                                          "application/x-gst-metadata",
272                                                                                                                          gst_props_new (
273                                                                                                                                  "identifier", G_TYPE_INT (labl.identifier),
274                                                                                                                                  "name", G_TYPE_STRING (label_name),
275                                                                                                                                  NULL));
276       
277       if (gst_props_get (props, "labels", &caps, NULL)) {
278                                 caps = g_list_append (caps, new_caps);
279       } else {
280                                 caps = g_list_append (NULL, new_caps);
281                                 
282                                 entry = gst_props_entry_new ("labels", GST_PROPS_GLIST (caps));
283                                 gst_props_add_entry (props, entry);
284       }
285       
286       break;
287       
288     case GST_RIFF_adtl_ltxt:
289       got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (struct _gst_riff_ltxt));
290       if (got_bytes != sizeof (struct _gst_riff_ltxt)) {
291         return;
292       }
293       
294       temp_ltxt = (struct _gst_riff_ltxt *) tempdata;
295       ltxt.id = GUINT32_FROM_LE (temp_ltxt->id);
296       ltxt.size = GUINT32_FROM_LE (temp_ltxt->size);
297       ltxt.identifier = GUINT32_FROM_LE (temp_ltxt->identifier);
298       ltxt.length = GUINT32_FROM_LE (temp_ltxt->length);
299       ltxt.purpose = GUINT32_FROM_LE (temp_ltxt->purpose);
300       ltxt.country = GUINT16_FROM_LE (temp_ltxt->country);
301       ltxt.language = GUINT16_FROM_LE (temp_ltxt->language);
302       ltxt.dialect = GUINT16_FROM_LE (temp_ltxt->dialect);
303       ltxt.codepage = GUINT16_FROM_LE (temp_ltxt->codepage);
304
305       gst_bytestream_flush (bs, sizeof (struct _gst_riff_ltxt));
306       len -= sizeof (struct _gst_riff_ltxt);
307
308                         if (ltxt.size - 20 > 0) {
309                                 got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, ltxt.size - 20);
310                                 if (got_bytes != ltxt.size - 20) {
311                                         return;
312                                 }
313                                 
314                                 gst_bytestream_flush (bs, ((ltxt.size - 20) + 1) & ~1);
315                                 len -= (( (ltxt.size - 20) + 1) & ~1);
316
317                                 label_name = (char *) tempdata;
318                         } else {
319                                 label_name = "";
320                         }
321                         
322       new_caps = gst_caps_new ("ltxt",
323                                                                                                                          "application/x-gst-metadata",
324                                                                                                                          gst_props_new (
325                                                                                                                                  "identifier", G_TYPE_INT (ltxt.identifier),
326                                                                                                                                  "name", G_TYPE_STRING (label_name),
327                                                                                                                                  "length", G_TYPE_INT (ltxt.length),
328                                                                                                                                  NULL));
329                         
330       if (gst_props_get (props, "ltxts", &caps, NULL)) {
331                                 caps = g_list_append (caps, new_caps);
332       } else {
333                                 caps = g_list_append (NULL, new_caps);
334                                 
335                                 entry = gst_props_entry_new ("ltxts", GST_PROPS_GLIST (caps));
336                                 gst_props_add_entry (props, entry);
337       }
338       
339       break;
340                         
341     case GST_RIFF_adtl_note:
342       got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (struct _gst_riff_note));
343       if (got_bytes != sizeof (struct _gst_riff_note)) {
344                                 return;
345       }
346       
347       temp_note = (struct _gst_riff_note *) tempdata;
348       note.id = GUINT32_FROM_LE (temp_note->id);
349       note.size = GUINT32_FROM_LE (temp_note->size);
350       note.identifier = GUINT32_FROM_LE (temp_note->identifier);
351       
352       gst_bytestream_flush (bs, sizeof (struct _gst_riff_note));
353       len -= sizeof (struct _gst_riff_note);
354                         
355       got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, note.size - 4);
356       if (got_bytes != note.size - 4) {
357                                 return;
358       }
359                         
360       gst_bytestream_flush (bs, ((note.size - 4) + 1) & ~1);
361       len -= (( (note.size - 4) + 1) & ~1);
362                         
363       label_name = (char *) tempdata;
364       
365       new_caps = gst_caps_new ("note",
366                                                                                                                          "application/x-gst-metadata",
367                                                                                                                          gst_props_new (
368                                                                                                                                  "identifier", G_TYPE_INT (note.identifier),
369                                                                                                                                  "name", G_TYPE_STRING (label_name),
370                                                                                                                                  NULL));
371       
372       if (gst_props_get (props, "notes", &caps, NULL)) {
373                                 caps = g_list_append (caps, new_caps);
374       } else {
375                                 caps = g_list_append (NULL, new_caps);
376                                 
377                                 entry = gst_props_entry_new ("notes", GST_PROPS_GLIST (caps));
378                                 gst_props_add_entry (props, entry);
379       }
380                         
381       break;      
382       
383     default:
384       g_print ("Unknown chunk: " GST_FOURCC_FORMAT "\n", GST_FOURCC_ARGS(chunk.id));
385       return;
386     }
387   }
388
389   g_object_notify (G_OBJECT (wavparse), "metadata");
390 }
391 #endif
392
393 #if 0
394 static void
395 gst_wavparse_parse_info (GstWavParse *wavparse,
396                                                                                                  int len)
397 {
398   gst_riff_chunk *temp_chunk, chunk;
399   GstByteStream *bs = wavparse->bs;
400   guint8 *tempdata;
401   guint32 got_bytes;
402   char *name, *type;
403   
404   while (len > 0) {
405     got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (gst_riff_chunk));
406     temp_chunk = (gst_riff_chunk *) tempdata;
407     
408     chunk.id = GUINT32_FROM_LE (temp_chunk->id);
409     chunk.size = GUINT32_FROM_LE (temp_chunk->size);
410
411     gst_bytestream_flush (bs, sizeof (gst_riff_chunk));
412     if (got_bytes != sizeof (gst_riff_chunk)) {
413       return;
414     }
415                                                  
416     /* move our pointer on past the header */
417     len -= sizeof (gst_riff_chunk);
418     
419     if (chunk.size == 0) {
420       continue;
421     }
422     
423     got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, chunk.size);
424     name = (char *) tempdata;
425     if (got_bytes != chunk.size) {
426       return;
427     }
428     
429     /* move our pointer on past the data ... on an even boundary */
430                 gst_bytestream_flush (bs, (chunk.size + 1) & ~1);
431     len -= ((chunk.size + 1) & ~1);
432
433     /* We now have an info string in 'name' of type chunk.id
434        - find type */
435     switch (chunk.id) {
436     case GST_RIFF_INFO_IARL:
437       type = "Location";
438       break;
439       
440     case GST_RIFF_INFO_IART:
441       type = "Artist";
442       break;
443       
444     case GST_RIFF_INFO_ICMS:
445       type = "Commissioner";
446       break;
447       
448     case GST_RIFF_INFO_ICMT:
449       type = "Comment";
450       break;
451       
452     case GST_RIFF_INFO_ICOP:
453       type = "Copyright";
454       break;
455       
456     case GST_RIFF_INFO_ICRD:
457       type = "Creation Date";
458       break;
459       
460     case GST_RIFF_INFO_IENG:
461       type = "Engineer";
462       break;
463       
464     case GST_RIFF_INFO_IGNR:
465       type = "Genre";
466       break;
467       
468     case GST_RIFF_INFO_IKEY:
469       type = "Keywords";
470       break;
471       
472     case GST_RIFF_INFO_INAM:
473       type = "Title"; /* name */
474       break;
475       
476     case GST_RIFF_INFO_IPRD:
477       type = "Product";
478       break;
479       
480     case GST_RIFF_INFO_ISBJ:
481       type = "Subject";
482       break;
483       
484     case GST_RIFF_INFO_ISFT:
485       type = "Software";
486       break;
487       
488     case GST_RIFF_INFO_ITCH:
489       type = "Technician";
490       break;
491       
492     default:
493       g_print ("Unknown: %4.4s\n", (char *) &chunk.id);
494       type = NULL;
495       break;
496     }
497
498     if (type) {
499       GstPropsEntry *entry;
500
501       entry = gst_props_entry_new (type, G_TYPE_STRING (name));
502       gst_props_add_entry (wavparse->metadata->properties, entry);
503     }
504   }
505
506   g_object_notify (G_OBJECT (wavparse), "metadata");
507 }
508 #endif
509
510 #if 0
511 static void
512 gst_wavparse_parse_cues (GstWavParse *wavparse,
513                          int len)
514 {
515   guint32 got_bytes;
516   GstByteStream *bs = wavparse->bs;
517   struct _gst_riff_cue *temp_cue, cue;
518   struct _gst_riff_cuepoints *points;
519   guint8 *tempdata;
520   int i;
521   GList *cues = NULL;
522   GstPropsEntry *entry;
523
524   while (len > 0) {
525     int required;
526     
527     got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (struct _gst_riff_cue));
528     temp_cue = (struct _gst_riff_cue *) tempdata;
529
530     /* fixup for our big endian friends */
531     cue.id = GUINT32_FROM_LE (temp_cue->id);
532     cue.size = GUINT32_FROM_LE (temp_cue->size);
533     cue.cuepoints = GUINT32_FROM_LE (temp_cue->cuepoints);
534
535     gst_bytestream_flush (bs, sizeof (struct _gst_riff_cue));
536     if (got_bytes != sizeof (struct _gst_riff_cue)) {
537       return;
538     }
539
540     len -= sizeof (struct _gst_riff_cue);
541
542     /* -4 because cue.size contains the cuepoints size
543        and we've already flushed that out of the system */
544     required = cue.size - 4;
545     got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, required);
546     gst_bytestream_flush (bs, ((required) + 1) & ~1);
547     if (got_bytes != required) {
548       return;
549     }
550
551     len -= ( ((cue.size - 4) + 1) & ~1);
552
553     /* now we have an array of struct _gst_riff_cuepoints in tempdata */
554     points = (struct _gst_riff_cuepoints *) tempdata;
555     
556     for (i = 0; i < cue.cuepoints; i++) {
557       GstCaps *caps;
558
559       caps = gst_caps_new ("cues",
560                                                                                                          "application/x-gst-metadata",
561                                                                                                          gst_props_new (
562                                                                                                                  "identifier", G_TYPE_INT (points[i].identifier),
563                                                                                                                  "position", G_TYPE_INT (points[i].offset),
564                                                                                                                  NULL));
565       cues = g_list_append (cues, caps);
566     }
567     
568     entry = gst_props_entry_new ("cues", GST_PROPS_GLIST (cues));
569     gst_props_add_entry (wavparse->metadata->properties, entry);
570   }
571   
572   g_object_notify (G_OBJECT (wavparse), "metadata");
573 }
574 #endif
575
576 static void
577 gst_wavparse_parse_fmt (GstWavParse *wavparse, guint size)
578 {
579   GstWavParseFormat *format;
580   GstCaps *caps = NULL;
581   guint8 *fmtdata;
582   GstByteStream *bs = wavparse->bs;
583   guint32 got_bytes;
584
585   got_bytes = gst_bytestream_peek_bytes (bs, &fmtdata, sizeof (GstWavParseFormat));
586   format = (GstWavParseFormat *) fmtdata;
587
588   if (got_bytes == sizeof (GstWavParseFormat)) {
589     gst_bytestream_flush (bs, size);
590     wavparse->bps = GUINT16_FROM_LE (format->wBlockAlign);
591     wavparse->rate = GUINT32_FROM_LE (format->dwSamplesPerSec);
592     wavparse->channels = GUINT16_FROM_LE (format->wChannels);
593     wavparse->width = GUINT16_FROM_LE (format->wBitsPerSample);
594     wavparse->format = GINT16_FROM_LE (format->wFormatTag);
595
596     /* set the caps on the src pad */
597     /* FIXME: handle all of the other formats as well */
598     switch (wavparse->format) {
599     case GST_RIFF_WAVE_FORMAT_ALAW:
600     case GST_RIFF_WAVE_FORMAT_MULAW: {
601       char *mime = (wavparse->format == GST_RIFF_WAVE_FORMAT_ALAW) ?
602                                 "audio/x-alaw" : "audio/x-mulaw";
603       if (wavparse->width != 8) {
604                                 g_warning ("Ignoring invalid width %d", wavparse->width);
605                                 return;
606       }
607                         
608       caps = gst_caps_new_simple (mime,
609         "rate", G_TYPE_INT, wavparse->rate,
610         "channels", G_TYPE_INT, wavparse->channels,
611         NULL);
612     }
613                         
614     case GST_RIFF_WAVE_FORMAT_PCM:
615       caps = gst_caps_new_simple ("audio/x-raw-int",
616         "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
617         "signed", G_TYPE_BOOLEAN, (wavparse->width > 8) ? TRUE : FALSE,
618         "width", G_TYPE_INT, wavparse->width,
619         "depth", G_TYPE_INT, wavparse->width,
620         "rate", G_TYPE_INT, wavparse->rate,
621         "channels", G_TYPE_INT, wavparse->channels,
622         NULL);
623       break;
624                         
625     case GST_RIFF_WAVE_FORMAT_MPEGL12:
626     case GST_RIFF_WAVE_FORMAT_MPEGL3: {
627       int layer = (wavparse->format == GST_RIFF_WAVE_FORMAT_MPEGL12) ? 2 : 3;
628                         
629       caps = gst_caps_new_simple ("audio/mpeg",
630           "mpegversion", G_TYPE_INT, 1,
631           "layer", G_TYPE_INT, layer,
632           "rate", G_TYPE_INT, wavparse->rate,
633           "channels", G_TYPE_INT, wavparse->channels,
634           NULL);
635     }
636       break;
637                         
638     default:
639       GST_ELEMENT_ERROR (wavparse, STREAM, NOT_IMPLEMENTED, (NULL), ("format %d not handled", wavparse->format));
640       return;
641     }
642
643     if (caps)
644         gst_pad_set_explicit_caps (wavparse->srcpad, caps);
645
646     GST_DEBUG ("frequency %d, channels %d",
647                                                          wavparse->rate, wavparse->channels);
648   }
649 }
650
651 static gboolean
652 gst_wavparse_handle_sink_event (GstWavParse *wavparse)
653 {
654   guint32 remaining;
655   GstEvent *event;
656   GstEventType type;
657   gboolean res = TRUE;
658         
659   gst_bytestream_get_status (wavparse->bs, &remaining, &event);
660         
661   type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
662   GST_DEBUG ("wavparse: event %p %d", event, type);
663         
664   switch (type) {
665   case GST_EVENT_EOS:
666     gst_bytestream_flush (wavparse->bs, remaining);
667     gst_pad_event_default (wavparse->sinkpad, event);
668     res = FALSE;
669     goto done;
670
671   case GST_EVENT_FLUSH:
672     g_warning ("Wavparse: Flush event");
673     break;
674
675   default:
676     g_warning ("Wavparse: Unhandled event %d", type);
677     break;
678   }
679
680   gst_event_unref (event);
681
682  done:
683   return res;
684 }
685     
686 static void
687 gst_wavparse_loop (GstElement *element)
688 {
689   GstWavParse *wavparse;
690   gst_riff_riff chunk;
691   guint32 flush = 0;
692   guint32 got_bytes;
693   GstByteStream *bs;
694
695   wavparse = GST_WAVPARSE (element);
696
697   bs = wavparse->bs;
698
699   if (wavparse->seek_pending) {
700     GST_DEBUG ("wavparse: seek pending to %" G_GINT64_FORMAT " %08llx",
701                wavparse->seek_offset,
702                (unsigned long long) wavparse->seek_offset);
703     
704     if (!gst_bytestream_seek (bs, wavparse->seek_offset, GST_SEEK_METHOD_SET)) {
705       GST_INFO ("wavparse: Could not seek");
706     }
707                 
708     wavparse->seek_pending = FALSE;
709   }
710         
711   if (wavparse->state == GST_WAVPARSE_DATA) {
712     GstBuffer *buf;
713     int desired;
714     
715     /* This seems to want the whole chunk,
716        Will this screw up streaming?
717        Does anyone care about streaming wavs?
718        FIXME: Should we have a decent buffer size? */
719                 
720 #define MAX_BUFFER_SIZE 1024
721
722     if (wavparse->dataleft > 0) {
723       desired = MIN (wavparse->dataleft, MAX_BUFFER_SIZE);
724       got_bytes = gst_bytestream_peek (bs, &buf, desired);
725
726       if (got_bytes != desired) {
727         /* EOS? */
728         GstEvent *event;
729         guint32 remaining;
730         gst_bytestream_get_status (bs, &remaining, &event);
731         if (event && GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
732           gst_pad_event_default (wavparse->sinkpad, event);
733         } else {
734           GST_ELEMENT_ERROR (element, RESOURCE, READ, (NULL), (NULL));
735         }
736         return;
737       }
738
739       wavparse->dataleft -= got_bytes;
740       wavparse->byteoffset += got_bytes;
741
742       gst_bytestream_flush (bs, got_bytes);
743                         
744       gst_pad_push (wavparse->srcpad, GST_DATA (buf));
745       return;
746     } else {
747       wavparse->state = GST_WAVPARSE_OTHER;
748     }
749   }
750
751   do {
752     gst_riff_riff *temp_chunk;
753     guint8 *tempdata;
754     guint32 skipsize;
755                 
756     /* read first two dwords to get chunktype and size */
757     while (TRUE) {
758       got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (gst_riff_chunk));
759       temp_chunk = (gst_riff_riff *) tempdata;
760
761       if (got_bytes < sizeof (gst_riff_chunk)) {
762                                 if (!gst_wavparse_handle_sink_event (wavparse)) {
763                                         return;
764                                 }
765       } else {
766                                 break;
767       }
768     }
769                 
770     chunk.id = GUINT32_FROM_LE (temp_chunk->id);
771     chunk.size = GUINT32_FROM_LE (temp_chunk->size);
772
773     switch (chunk.id) {
774     case GST_RIFF_TAG_RIFF:
775     case GST_RIFF_TAG_LIST:
776       /* Read complete list chunk */
777       while (TRUE) {
778         got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (gst_riff_list));
779         temp_chunk = (gst_riff_riff *) tempdata;
780         if (got_bytes < sizeof (gst_riff_list)) {
781           if (!gst_wavparse_handle_sink_event (wavparse)) {
782             return;
783           }
784         } else {
785           break;
786         }
787       }
788                         
789       chunk.type = GUINT32_FROM_LE (temp_chunk->type);
790       skipsize = sizeof (gst_riff_list);
791       break;
792
793     case GST_RIFF_TAG_cue:
794       skipsize = 0;
795       break;
796       
797     default:
798       skipsize = sizeof (gst_riff_chunk);
799       break;
800     }
801     gst_bytestream_flush (bs, skipsize);
802   } while (FALSE);
803
804   /* need to flush an even number of bytes at the end */
805   flush = (chunk.size + 1) & ~1;
806
807   switch (wavparse->state) {
808   case GST_WAVPARSE_START:
809     if (chunk.id != GST_RIFF_TAG_RIFF &&
810                                 chunk.type != GST_RIFF_RIFF_WAVE) {
811       GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL),
812                            ("chunk.id %08x chunk.type %08x", chunk.id, chunk.type));
813       return;
814     }
815                 
816     wavparse->state = GST_WAVPARSE_OTHER;
817     /* We are not going to flush lists */
818     flush = 0;
819     break;
820
821   case GST_WAVPARSE_OTHER:
822     GST_DEBUG ("riff tag: %4.4s %08x", (char *) &chunk.id, chunk.size);
823                 
824     switch (chunk.id) {
825     case GST_RIFF_TAG_data:
826       wavparse->state = GST_WAVPARSE_DATA;
827       wavparse->dataleft = chunk.size;
828       wavparse->byteoffset = 0;
829       flush = 0;
830       break;
831       
832     case GST_RIFF_TAG_fmt:
833       gst_wavparse_parse_fmt (wavparse, chunk.size);
834       flush = 0;
835       break;
836
837     case GST_RIFF_TAG_cue:
838       //gst_wavparse_parse_cues (wavparse, chunk.size);
839       break;
840       
841     case GST_RIFF_TAG_LIST:
842       GST_DEBUG ("list type: %4.4s", (char *) &chunk.type);
843       switch (chunk.type) {
844       case GST_RIFF_LIST_INFO:
845         //gst_wavparse_parse_info (wavparse, chunk.size - 4);
846         //flush = 0;
847
848         break;
849                                 
850       case GST_RIFF_LIST_adtl:
851         //gst_wavparse_parse_adtl (wavparse, chunk.size - 4);
852         //flush = 0;
853         break;
854
855       default:
856         //flush = 0;
857         break;
858       }
859       
860     default:
861       GST_DEBUG ("  *****  unknown chunkid %08x", chunk.id);
862       //flush = 0;
863       break;      
864     }
865     break;
866                 
867   case GST_WAVPARSE_DATA:
868                 /* Should have been handled up there ^^^^ */
869                 flush = 0;
870     break;
871                 
872   default:
873     /* Unknown */
874     g_warning ("Unknown state %d\n", wavparse->state);
875     //GST_DEBUG ("  *****  unknown chunkid %08x", chunk.id);
876     break;
877   }
878
879   if (flush > 0) {
880     gboolean res;
881
882     res = gst_bytestream_flush (bs, flush);
883     if (!res) {
884       guint32 remaining;
885       GstEvent *event;
886
887       gst_bytestream_get_status (bs, &remaining, &event);
888       gst_event_unref (event);
889     } 
890   }
891 }
892
893 /* convert and query stuff */
894 static const GstFormat *
895 gst_wavparse_get_formats (GstPad *pad)
896 {
897   static GstFormat formats[] = {
898     GST_FORMAT_TIME,
899     GST_FORMAT_BYTES,
900     GST_FORMAT_DEFAULT, /* a "frame", ie a set of samples per Hz */
901     0,
902     0
903   };
904   return formats;
905 }
906
907 static gboolean
908 gst_wavparse_pad_convert (GstPad *pad,
909                           GstFormat src_format, gint64 src_value,
910                           GstFormat *dest_format, gint64 *dest_value)
911 {
912   gint bytes_per_sample;
913   glong byterate;
914   GstWavParse *wavparse;
915
916   wavparse = GST_WAVPARSE (gst_pad_get_parent (pad));
917   
918   bytes_per_sample = wavparse->channels * wavparse->width / 8;
919   if (bytes_per_sample == 0) {
920     GST_DEBUG ("bytes_per_sample is 0, probably an mp3 - channels %d,  width %d\n",
921                   wavparse->channels, wavparse->width);
922     return FALSE;
923   }
924   byterate = (glong) (bytes_per_sample * wavparse->rate);
925   if (byterate == 0) {
926     g_warning ("byterate is 0, internal error\n");
927     return FALSE;
928   }
929   GST_DEBUG ("bytes per sample: %d\n", bytes_per_sample);
930
931   switch (src_format) {
932     case GST_FORMAT_BYTES:
933       if (*dest_format == GST_FORMAT_DEFAULT)
934         *dest_value = src_value / bytes_per_sample;
935       else if (*dest_format == GST_FORMAT_TIME)
936         *dest_value = src_value * GST_SECOND / byterate;
937       else
938         return FALSE;
939       break;
940     case GST_FORMAT_DEFAULT:
941       if (*dest_format == GST_FORMAT_BYTES)
942         *dest_value = src_value * bytes_per_sample;
943       else if (*dest_format == GST_FORMAT_TIME)
944         *dest_value = src_value * GST_SECOND / wavparse->rate;
945       else
946         return FALSE;
947       break;
948     case GST_FORMAT_TIME:
949       if (*dest_format == GST_FORMAT_BYTES)
950         *dest_value = src_value * byterate / GST_SECOND;
951       else if (*dest_format == GST_FORMAT_DEFAULT)
952         *dest_value = src_value * wavparse->rate / GST_SECOND;
953       else
954         return FALSE;
955
956       *dest_value = *dest_value & ~(bytes_per_sample - 1);
957       break;
958     default:
959       g_warning ("unhandled format for wavparse\n");
960       break;
961   }
962   return TRUE;
963 }
964       
965 static const GstQueryType *
966 gst_wavparse_get_query_types (GstPad *pad)
967 {
968   static const GstQueryType types[] = {
969     GST_QUERY_TOTAL,
970     GST_QUERY_POSITION,
971     0
972   };
973   return types;
974 }
975
976 /* handle queries for location and length in requested format */
977 static gboolean
978 gst_wavparse_pad_query (GstPad *pad, GstQueryType type,
979                         GstFormat *format, gint64 *value)
980 {
981   GstFormat peer_format = GST_FORMAT_BYTES;
982   gint64 peer_value;
983   GstWavParse *wavparse;
984
985   /* probe sink's peer pad, convert value, and that's it :) */
986   /* FIXME: ideally we'd loop over possible formats of peer instead
987    * of only using BYTE */
988   wavparse = GST_WAVPARSE (gst_pad_get_parent (pad));
989   if (!gst_pad_query (GST_PAD_PEER (wavparse->sinkpad), type, 
990                       &peer_format, &peer_value)) {
991     g_warning ("Could not query sink pad's peer\n");
992     return FALSE;
993   }
994   if (!gst_pad_convert (wavparse->sinkpad, peer_format, peer_value,
995                         format, value)) {
996     g_warning ("Could not query sink pad's peer\n");
997     return FALSE;
998   }
999   GST_DEBUG ("pad_query done, value %" G_GINT64_FORMAT "\n", *value);
1000   return TRUE;
1001 }
1002
1003 static const GstEventMask*
1004 gst_wavparse_get_event_masks (GstPad *pad)
1005
1006   static const GstEventMask gst_wavparse_src_event_masks[] = {
1007     { GST_EVENT_SEEK, GST_SEEK_METHOD_SET |
1008                       GST_SEEK_FLAG_FLUSH },
1009     { 0, }
1010   };
1011   return gst_wavparse_src_event_masks;
1012 }   
1013
1014 static gboolean
1015 gst_wavparse_srcpad_event (GstPad *pad, GstEvent *event)
1016 {
1017 #if 0
1018   GstWavParse *wavparse = GST_WAVPARSE (GST_PAD_PARENT (pad));
1019   gboolean res = FALSE;
1020
1021   GST_DEBUG ("event %d", GST_EVENT_TYPE (event));
1022
1023   switch (GST_EVENT_TYPE (event)) {
1024     case GST_EVENT_SEEK:
1025     {
1026       gint64 byteoffset;
1027       GstFormat format;
1028
1029       /* we can only seek when in the DATA state */
1030       if (wavparse->state != GST_WAVPARSE_DATA) {
1031         return FALSE;
1032       }
1033
1034       format = GST_FORMAT_BYTES;
1035       
1036       /* bring format to bytes for the peer element, 
1037        * FIXME be smarter here */
1038       res = gst_pad_convert (pad, 
1039                              GST_EVENT_SEEK_FORMAT (event),
1040                              GST_EVENT_SEEK_OFFSET (event),
1041                              &format,
1042                              &byteoffset);
1043       
1044       if (res) {
1045         /* ok, seek worked, update our state */
1046         wavparse->seek_offset = byteoffset;
1047         wavparse->seek_pending = TRUE;
1048         wavparse->need_discont = TRUE;
1049       }
1050       break;
1051     }
1052     default:
1053       break;
1054   }
1055
1056   gst_event_unref (event);
1057   return res;
1058 #else
1059   return FALSE;
1060 #endif
1061 }
1062
1063 static GstElementStateReturn
1064 gst_wavparse_change_state (GstElement *element)
1065 {
1066   GstWavParse *wavparse = GST_WAVPARSE (element);
1067
1068   switch (GST_STATE_TRANSITION (element)) {
1069     case GST_STATE_NULL_TO_READY:
1070       break;
1071     case GST_STATE_READY_TO_PAUSED:
1072       wavparse->bs = gst_bytestream_new (wavparse->sinkpad);
1073       wavparse->state = GST_WAVPARSE_START;
1074       break;
1075     case GST_STATE_PAUSED_TO_PLAYING:
1076       break;
1077     case GST_STATE_PLAYING_TO_PAUSED:
1078       break;
1079     case GST_STATE_PAUSED_TO_READY:
1080       gst_bytestream_destroy (wavparse->bs);
1081       wavparse->state = GST_WAVPARSE_UNKNOWN;
1082       wavparse->bps = 0;
1083       wavparse->seek_pending = FALSE;
1084       wavparse->seek_offset = 0;
1085       break;
1086     case GST_STATE_READY_TO_NULL:
1087       break;
1088   }
1089
1090   if (GST_ELEMENT_CLASS (parent_class)->change_state)
1091     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
1092
1093   return GST_STATE_SUCCESS;
1094 }
1095
1096 static gboolean
1097 plugin_init (GstPlugin *plugin)
1098 {
1099   if (!gst_library_load ("gstbytestream")) {
1100     return FALSE;
1101   }
1102
1103   return gst_element_register (plugin, "wavparse", GST_RANK_SECONDARY, GST_TYPE_WAVPARSE);
1104 }
1105
1106 GST_PLUGIN_DEFINE (
1107   GST_VERSION_MAJOR,
1108   GST_VERSION_MINOR,
1109   "wavparse",
1110   "Parse a .wav file into raw audio",
1111   plugin_init,
1112   VERSION,
1113   GST_LICENSE,
1114   GST_PACKAGE,
1115   GST_ORIGIN
1116 )