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