gst/wavparse/gstwavparse.*: Added some more debugging info.
[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 #include "gst/riff/riff-ids.h"
29 #include "gst/riff/riff-media.h"
30
31 GST_DEBUG_CATEGORY (wavparse_debug);
32 #define GST_CAT_DEFAULT (wavparse_debug)
33
34 static void gst_wavparse_base_init (gpointer g_class);
35 static void gst_wavparse_class_init (GstWavParseClass * klass);
36 static void gst_wavparse_init (GstWavParse * wavparse);
37
38 static GstElementStateReturn gst_wavparse_change_state (GstElement * element);
39
40 static const GstFormat *gst_wavparse_get_formats (GstPad * pad);
41 static const GstQueryType *gst_wavparse_get_query_types (GstPad * pad);
42 static gboolean gst_wavparse_pad_query (GstPad * pad,
43     GstQueryType type, GstFormat * format, gint64 * value);
44 static gboolean gst_wavparse_pad_convert (GstPad * pad,
45     GstFormat src_format,
46     gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
47
48 static void gst_wavparse_loop (GstElement * element);
49 static const GstEventMask *gst_wavparse_get_event_masks (GstPad * pad);
50 static gboolean gst_wavparse_srcpad_event (GstPad * pad, GstEvent * event);
51 static void gst_wavparse_get_property (GObject * object, guint prop_id,
52     GValue * value, GParamSpec * pspec);
53
54 static GstStaticPadTemplate sink_template_factory =
55 GST_STATIC_PAD_TEMPLATE ("wavparse_sink",
56     GST_PAD_SINK,
57     GST_PAD_ALWAYS,
58     GST_STATIC_CAPS ("audio/x-wav")
59     );
60
61 static GstStaticPadTemplate src_template_factory =
62     GST_STATIC_PAD_TEMPLATE ("wavparse_src",
63     GST_PAD_SRC,
64     GST_PAD_SOMETIMES,          /* FIXME: spider */
65     GST_STATIC_CAPS ("audio/x-raw-int, "
66         "endianness = (int) little_endian, "
67         "signed = (boolean) { true, false }, "
68         "width = (int) { 8, 16 }, "
69         "depth = (int) { 8, 16 }, "
70         "rate = (int) [ 8000, 48000 ], "
71         "channels = (int) [ 1, 2 ]; "
72         "audio/mpeg, "
73         "mpegversion = (int) 1, "
74         "layer = (int) [ 1, 3 ], "
75         "rate = (int) [ 8000, 48000 ], "
76         "channels = (int) [ 1, 2 ]; "
77         "audio/x-alaw, "
78         "rate = (int) [ 8000, 48000 ], "
79         "channels = (int) [ 1, 2 ]; "
80         "audio/x-mulaw, "
81         "rate = (int) [ 8000, 48000 ], " "channels = (int) [ 1, 2 ];"
82         "audio/x-adpcm, "
83         "layout = (string) microsoft, "
84         "block_align = (int) [ 1, 8192 ], "
85         "rate = (int) [ 8000, 48000 ], "
86         "channels = (int) [ 1, 2 ]; "
87         "audio/x-adpcm, "
88         "layout = (string) dvi, "
89         "block_align = (int) [ 1, 8192 ], "
90         "rate = (int) [ 8000, 48000 ], " "channels = (int) [ 1, 2 ]")
91     );
92
93 /* WavParse signals and args */
94 enum
95 {
96   /* FILL ME */
97   LAST_SIGNAL
98 };
99
100 enum
101 {
102   PROP_0
103 };
104
105 static GstElementClass *parent_class = NULL;
106
107 /*static guint gst_wavparse_signals[LAST_SIGNAL] = { 0 }; */
108
109 GType
110 gst_wavparse_get_type (void)
111 {
112   static GType wavparse_type = 0;
113
114   if (!wavparse_type) {
115     static const GTypeInfo wavparse_info = {
116       sizeof (GstWavParseClass),
117       gst_wavparse_base_init,
118       NULL,
119       (GClassInitFunc) gst_wavparse_class_init,
120       NULL,
121       NULL,
122       sizeof (GstWavParse),
123       0,
124       (GInstanceInitFunc) gst_wavparse_init,
125     };
126
127     wavparse_type =
128         g_type_register_static (GST_TYPE_RIFF_READ, "GstWavParse",
129         &wavparse_info, 0);
130   }
131   return wavparse_type;
132 }
133
134
135 static void
136 gst_wavparse_base_init (gpointer g_class)
137 {
138   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
139   static GstElementDetails gst_wavparse_details =
140       GST_ELEMENT_DETAILS (".wav demuxer",
141       "Codec/Demuxer/Audio",
142       "Parse a .wav file into raw audio",
143       "Erik Walthinsen <omega@cse.ogi.edu>");
144
145   gst_element_class_set_details (element_class, &gst_wavparse_details);
146
147   /* register src pads */
148   gst_element_class_add_pad_template (element_class,
149       gst_static_pad_template_get (&sink_template_factory));
150   gst_element_class_add_pad_template (element_class,
151       gst_static_pad_template_get (&src_template_factory));
152 }
153
154 static void
155 gst_wavparse_class_init (GstWavParseClass * klass)
156 {
157   GstElementClass *gstelement_class;
158   GObjectClass *object_class;
159
160   gstelement_class = (GstElementClass *) klass;
161   object_class = (GObjectClass *) klass;
162
163   parent_class = g_type_class_ref (GST_TYPE_RIFF_READ);
164
165   object_class->get_property = gst_wavparse_get_property;
166   gstelement_class->change_state = gst_wavparse_change_state;
167
168   GST_DEBUG_CATEGORY_INIT (wavparse_debug, "wavparse", 0, "WAV parser");
169 }
170
171 static void
172 gst_wavparse_init (GstWavParse * wavparse)
173 {
174   /* sink */
175   wavparse->sinkpad =
176       gst_pad_new_from_template (gst_static_pad_template_get
177       (&sink_template_factory), "sink");
178   gst_element_add_pad (GST_ELEMENT (wavparse), wavparse->sinkpad);
179   GST_RIFF_READ (wavparse)->sinkpad = wavparse->sinkpad;
180
181   gst_pad_set_formats_function (wavparse->sinkpad, gst_wavparse_get_formats);
182   gst_pad_set_convert_function (wavparse->sinkpad, gst_wavparse_pad_convert);
183   gst_pad_set_query_type_function (wavparse->sinkpad,
184       gst_wavparse_get_query_types);
185   gst_pad_set_query_function (wavparse->sinkpad, gst_wavparse_pad_query);
186
187 #if 0
188   /* source */
189   wavparse->srcpad =
190       gst_pad_new_from_template (gst_static_pad_template_get
191       (&src_template_factory), "src");
192   gst_pad_use_explicit_caps (wavparse->srcpad);
193   gst_element_add_pad (GST_ELEMENT (wavparse), wavparse->srcpad);
194   gst_pad_set_formats_function (wavparse->srcpad, gst_wavparse_get_formats);
195   gst_pad_set_convert_function (wavparse->srcpad, gst_wavparse_pad_convert);
196   gst_pad_set_query_type_function (wavparse->srcpad,
197       gst_wavparse_get_query_types);
198   gst_pad_set_query_function (wavparse->srcpad, gst_wavparse_pad_query);
199   gst_pad_set_event_function (wavparse->srcpad, gst_wavparse_srcpad_event);
200   gst_pad_set_event_mask_function (wavparse->srcpad,
201       gst_wavparse_get_event_masks);
202 #endif
203
204   gst_element_set_loop_function (GST_ELEMENT (wavparse), gst_wavparse_loop);
205
206   wavparse->state = GST_WAVPARSE_START;
207
208   /* These will all be set correctly in the fmt chunk */
209   wavparse->depth = 0;
210   wavparse->rate = 0;
211   wavparse->width = 0;
212   wavparse->channels = 0;
213
214   wavparse->seek_pending = FALSE;
215   wavparse->seek_offset = 0;
216 }
217
218 static void
219 gst_wavparse_destroy_sourcepad (GstWavParse * wavparse)
220 {
221   if (wavparse->srcpad) {
222     gst_element_remove_pad (GST_ELEMENT (wavparse), wavparse->srcpad);
223     wavparse->srcpad = NULL;
224   }
225 }
226
227 static void
228 gst_wavparse_create_sourcepad (GstWavParse * wavparse)
229 {
230   gst_wavparse_destroy_sourcepad (wavparse);
231
232   /* source */
233   wavparse->srcpad =
234       gst_pad_new_from_template (gst_static_pad_template_get
235       (&src_template_factory), "src");
236   gst_pad_use_explicit_caps (wavparse->srcpad);
237   gst_pad_set_formats_function (wavparse->srcpad, gst_wavparse_get_formats);
238   gst_pad_set_convert_function (wavparse->srcpad, gst_wavparse_pad_convert);
239   gst_pad_set_query_type_function (wavparse->srcpad,
240       gst_wavparse_get_query_types);
241   gst_pad_set_query_function (wavparse->srcpad, gst_wavparse_pad_query);
242   gst_pad_set_event_function (wavparse->srcpad, gst_wavparse_srcpad_event);
243   gst_pad_set_event_mask_function (wavparse->srcpad,
244       gst_wavparse_get_event_masks);
245 }
246
247 static void
248 gst_wavparse_get_property (GObject * object,
249     guint prop_id, GValue * value, GParamSpec * pspec)
250 {
251   GstWavParse *wavparse;
252
253   wavparse = GST_WAVPARSE (object);
254
255   switch (prop_id) {
256     default:
257       break;
258   }
259 }
260
261 #if 0
262 static void
263 gst_wavparse_parse_adtl (GstWavParse * wavparse, int len)
264 {
265   guint32 got_bytes;
266   GstByteStream *bs = wavparse->bs;
267   gst_riff_chunk *temp_chunk, chunk;
268   guint8 *tempdata;
269   struct _gst_riff_labl labl, *temp_labl;
270   struct _gst_riff_ltxt ltxt, *temp_ltxt;
271   struct _gst_riff_note note, *temp_note;
272   char *label_name;
273   GstProps *props;
274   GstPropsEntry *entry;
275   GstCaps *new_caps;
276   GList *caps = NULL;
277
278   props = wavparse->metadata->properties;
279
280   while (len > 0) {
281     got_bytes =
282         gst_bytestream_peek_bytes (bs, &tempdata, sizeof (gst_riff_chunk));
283     if (got_bytes != sizeof (gst_riff_chunk)) {
284       return;
285     }
286     temp_chunk = (gst_riff_chunk *) tempdata;
287
288     chunk.id = GUINT32_FROM_LE (temp_chunk->id);
289     chunk.size = GUINT32_FROM_LE (temp_chunk->size);
290
291     if (chunk.size == 0) {
292       gst_bytestream_flush (bs, sizeof (gst_riff_chunk));
293       len -= sizeof (gst_riff_chunk);
294       continue;
295     }
296
297     switch (chunk.id) {
298       case GST_RIFF_adtl_labl:
299         got_bytes =
300             gst_bytestream_peek_bytes (bs, &tempdata,
301             sizeof (struct _gst_riff_labl));
302         if (got_bytes != sizeof (struct _gst_riff_labl)) {
303           return;
304         }
305
306         temp_labl = (struct _gst_riff_labl *) tempdata;
307         labl.id = GUINT32_FROM_LE (temp_labl->id);
308         labl.size = GUINT32_FROM_LE (temp_labl->size);
309         labl.identifier = GUINT32_FROM_LE (temp_labl->identifier);
310
311         gst_bytestream_flush (bs, sizeof (struct _gst_riff_labl));
312         len -= sizeof (struct _gst_riff_labl);
313
314         got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, labl.size - 4);
315         if (got_bytes != labl.size - 4) {
316           return;
317         }
318
319         label_name = (char *) tempdata;
320
321         gst_bytestream_flush (bs, ((labl.size - 4) + 1) & ~1);
322         len -= (((labl.size - 4) + 1) & ~1);
323
324         new_caps = gst_caps_new ("label",
325             "application/x-gst-metadata",
326             gst_props_new ("identifier", G_TYPE_INT (labl.identifier),
327                 "name", G_TYPE_STRING (label_name), NULL));
328
329         if (gst_props_get (props, "labels", &caps, NULL)) {
330           caps = g_list_append (caps, new_caps);
331         } else {
332           caps = g_list_append (NULL, new_caps);
333
334           entry = gst_props_entry_new ("labels", GST_PROPS_GLIST (caps));
335           gst_props_add_entry (props, entry);
336         }
337
338         break;
339
340       case GST_RIFF_adtl_ltxt:
341         got_bytes =
342             gst_bytestream_peek_bytes (bs, &tempdata,
343             sizeof (struct _gst_riff_ltxt));
344         if (got_bytes != sizeof (struct _gst_riff_ltxt)) {
345           return;
346         }
347
348         temp_ltxt = (struct _gst_riff_ltxt *) tempdata;
349         ltxt.id = GUINT32_FROM_LE (temp_ltxt->id);
350         ltxt.size = GUINT32_FROM_LE (temp_ltxt->size);
351         ltxt.identifier = GUINT32_FROM_LE (temp_ltxt->identifier);
352         ltxt.length = GUINT32_FROM_LE (temp_ltxt->length);
353         ltxt.purpose = GUINT32_FROM_LE (temp_ltxt->purpose);
354         ltxt.country = GUINT16_FROM_LE (temp_ltxt->country);
355         ltxt.language = GUINT16_FROM_LE (temp_ltxt->language);
356         ltxt.dialect = GUINT16_FROM_LE (temp_ltxt->dialect);
357         ltxt.codepage = GUINT16_FROM_LE (temp_ltxt->codepage);
358
359         gst_bytestream_flush (bs, sizeof (struct _gst_riff_ltxt));
360         len -= sizeof (struct _gst_riff_ltxt);
361
362         if (ltxt.size - 20 > 0) {
363           got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, ltxt.size - 20);
364           if (got_bytes != ltxt.size - 20) {
365             return;
366           }
367
368           gst_bytestream_flush (bs, ((ltxt.size - 20) + 1) & ~1);
369           len -= (((ltxt.size - 20) + 1) & ~1);
370
371           label_name = (char *) tempdata;
372         } else {
373           label_name = "";
374         }
375
376         new_caps = gst_caps_new ("ltxt",
377             "application/x-gst-metadata",
378             gst_props_new ("identifier", G_TYPE_INT (ltxt.identifier),
379                 "name", G_TYPE_STRING (label_name),
380                 "length", G_TYPE_INT (ltxt.length), NULL));
381
382         if (gst_props_get (props, "ltxts", &caps, NULL)) {
383           caps = g_list_append (caps, new_caps);
384         } else {
385           caps = g_list_append (NULL, new_caps);
386
387           entry = gst_props_entry_new ("ltxts", GST_PROPS_GLIST (caps));
388           gst_props_add_entry (props, entry);
389         }
390
391         break;
392
393       case GST_RIFF_adtl_note:
394         got_bytes =
395             gst_bytestream_peek_bytes (bs, &tempdata,
396             sizeof (struct _gst_riff_note));
397         if (got_bytes != sizeof (struct _gst_riff_note)) {
398           return;
399         }
400
401         temp_note = (struct _gst_riff_note *) tempdata;
402         note.id = GUINT32_FROM_LE (temp_note->id);
403         note.size = GUINT32_FROM_LE (temp_note->size);
404         note.identifier = GUINT32_FROM_LE (temp_note->identifier);
405
406         gst_bytestream_flush (bs, sizeof (struct _gst_riff_note));
407         len -= sizeof (struct _gst_riff_note);
408
409         got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, note.size - 4);
410         if (got_bytes != note.size - 4) {
411           return;
412         }
413
414         gst_bytestream_flush (bs, ((note.size - 4) + 1) & ~1);
415         len -= (((note.size - 4) + 1) & ~1);
416
417         label_name = (char *) tempdata;
418
419         new_caps = gst_caps_new ("note",
420             "application/x-gst-metadata",
421             gst_props_new ("identifier", G_TYPE_INT (note.identifier),
422                 "name", G_TYPE_STRING (label_name), NULL));
423
424         if (gst_props_get (props, "notes", &caps, NULL)) {
425           caps = g_list_append (caps, new_caps);
426         } else {
427           caps = g_list_append (NULL, new_caps);
428
429           entry = gst_props_entry_new ("notes", GST_PROPS_GLIST (caps));
430           gst_props_add_entry (props, entry);
431         }
432
433         break;
434
435       default:
436         g_print ("Unknown chunk: " GST_FOURCC_FORMAT "\n",
437             GST_FOURCC_ARGS (chunk.id));
438         return;
439     }
440   }
441
442   g_object_notify (G_OBJECT (wavparse), "metadata");
443 }
444 #endif
445
446 #if 0
447 static void
448 gst_wavparse_parse_cues (GstWavParse * wavparse, int len)
449 {
450   guint32 got_bytes;
451   GstByteStream *bs = wavparse->bs;
452   struct _gst_riff_cue *temp_cue, cue;
453   struct _gst_riff_cuepoints *points;
454   guint8 *tempdata;
455   int i;
456   GList *cues = NULL;
457   GstPropsEntry *entry;
458
459   while (len > 0) {
460     int required;
461
462     got_bytes =
463         gst_bytestream_peek_bytes (bs, &tempdata,
464         sizeof (struct _gst_riff_cue));
465     temp_cue = (struct _gst_riff_cue *) tempdata;
466
467     /* fixup for our big endian friends */
468     cue.id = GUINT32_FROM_LE (temp_cue->id);
469     cue.size = GUINT32_FROM_LE (temp_cue->size);
470     cue.cuepoints = GUINT32_FROM_LE (temp_cue->cuepoints);
471
472     gst_bytestream_flush (bs, sizeof (struct _gst_riff_cue));
473     if (got_bytes != sizeof (struct _gst_riff_cue)) {
474       return;
475     }
476
477     len -= sizeof (struct _gst_riff_cue);
478
479     /* -4 because cue.size contains the cuepoints size
480        and we've already flushed that out of the system */
481     required = cue.size - 4;
482     got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, required);
483     gst_bytestream_flush (bs, ((required) + 1) & ~1);
484     if (got_bytes != required) {
485       return;
486     }
487
488     len -= (((cue.size - 4) + 1) & ~1);
489
490     /* now we have an array of struct _gst_riff_cuepoints in tempdata */
491     points = (struct _gst_riff_cuepoints *) tempdata;
492
493     for (i = 0; i < cue.cuepoints; i++) {
494       GstCaps *caps;
495
496       caps = gst_caps_new ("cues",
497           "application/x-gst-metadata",
498           gst_props_new ("identifier", G_TYPE_INT (points[i].identifier),
499               "position", G_TYPE_INT (points[i].offset), NULL));
500       cues = g_list_append (cues, caps);
501     }
502
503     entry = gst_props_entry_new ("cues", GST_PROPS_GLIST (cues));
504     gst_props_add_entry (wavparse->metadata->properties, entry);
505   }
506
507   g_object_notify (G_OBJECT (wavparse), "metadata");
508 }
509 #endif
510
511 static gboolean
512 gst_wavparse_stream_init (GstWavParse * wav)
513 {
514   GstRiffRead *riff = GST_RIFF_READ (wav);
515   guint32 doctype;
516
517   if (!gst_riff_read_header (riff, &doctype)) {
518     GST_WARNING_OBJECT (wav, "could not read header");
519     return FALSE;
520   }
521
522   if (doctype != GST_RIFF_RIFF_WAVE) {
523     GST_ELEMENT_ERROR (wav, STREAM, WRONG_TYPE, (NULL), (NULL));
524     return FALSE;
525   }
526
527   return TRUE;
528 }
529
530 /* Read 'fmt ' header */
531 static gboolean
532 gst_wavparse_fmt (GstWavParse * wav)
533 {
534   GstRiffRead *riff = GST_RIFF_READ (wav);
535   gst_riff_strf_auds *header = NULL;
536   GstCaps *caps;
537
538   if (!gst_riff_read_strf_auds (riff, &header)) {
539     g_warning ("Not fmt");
540     return FALSE;
541   }
542
543   wav->format = header->format;
544   wav->rate = header->rate;
545   wav->channels = header->channels;
546   wav->blockalign = header->blockalign;
547   wav->width = (header->blockalign * 8) / header->channels;
548   wav->depth = header->size;
549   wav->bps = header->av_bps;
550
551   caps = gst_riff_create_audio_caps (header->format, NULL, header, NULL);
552
553   if (caps) {
554     gst_wavparse_create_sourcepad (wav);
555     gst_pad_set_explicit_caps (wav->srcpad, caps);
556     gst_caps_free (caps);
557     gst_element_add_pad (GST_ELEMENT (wav), wav->srcpad);
558     GST_DEBUG ("frequency %d, channels %d", wav->rate, wav->channels);
559   } else {
560     GST_ELEMENT_ERROR (wav, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
561     return FALSE;
562   }
563
564
565
566   g_free (header);
567
568   return TRUE;
569 }
570
571 static gboolean
572 gst_wavparse_other (GstWavParse * wav)
573 {
574   GstRiffRead *riff = GST_RIFF_READ (wav);
575   guint32 tag, length;
576
577   if (!gst_riff_peek_head (riff, &tag, &length, NULL)) {
578     GST_WARNING_OBJECT (wav, "could not peek head");
579     return FALSE;
580   }
581   GST_DEBUG_OBJECT (wav, "got tag (%08x) %4.4s, length %d", tag,
582       (gchar *) & tag, length);
583
584   switch (tag) {
585     case GST_RIFF_TAG_LIST:
586       if (!(tag = gst_riff_peek_list (riff))) {
587         GST_WARNING_OBJECT (wav, "could not peek list");
588         return FALSE;
589       }
590
591       switch (tag) {
592         case GST_RIFF_LIST_INFO:
593           if (!gst_riff_read_list (riff, &tag) || !gst_riff_read_info (riff)) {
594             GST_WARNING_OBJECT (wav, "could not read list");
595             return FALSE;
596           }
597           break;
598
599         case GST_RIFF_LIST_adtl:
600           if (!gst_riff_read_skip (riff)) {
601             GST_WARNING_OBJECT (wav, "could not read skip");
602             return FALSE;
603           }
604           break;
605
606         default:
607           GST_DEBUG_OBJECT (wav, "skipping tag (%08x) %4.4s", tag,
608               (gchar *) & tag);
609           if (!gst_riff_read_skip (riff)) {
610             GST_WARNING_OBJECT (wav, "could not read skip");
611             return FALSE;
612           }
613           break;
614       }
615
616       break;
617
618     case GST_RIFF_TAG_data:
619       if (!gst_bytestream_flush (riff->bs, 8)) {
620         GST_WARNING_OBJECT (wav, "could not flush 8 bytes");
621         return FALSE;
622       }
623
624       GST_DEBUG_OBJECT (wav, "switching to data mode");
625       wav->state = GST_WAVPARSE_DATA;
626       wav->datastart = gst_bytestream_tell (riff->bs);
627       if (length == 0) {
628         guint64 file_length;
629
630         /* length is 0, data probably stretches to the end
631          * of file */
632         GST_DEBUG_OBJECT (wav, "length is 0 trying to find length");
633         /* get length of file */
634         file_length = gst_bytestream_length (riff->bs);
635         if (file_length == -1) {
636           GST_DEBUG_OBJECT (wav,
637               "could not get file length, assuming data to eof");
638           /* could not get length, assuming till eof */
639           length = G_MAXUINT32;
640         }
641         if (file_length > G_MAXUINT32) {
642           GST_DEBUG_OBJECT (wav, "file length %lld, clipping to 32 bits");
643           /* could not get length, assuming till eof */
644           length = G_MAXUINT32;
645         } else {
646           GST_DEBUG_OBJECT (wav, "file length %lld, datalength", file_length,
647               length);
648           /* substract offset of datastart from length */
649           length = file_length - wav->datastart;
650           GST_DEBUG_OBJECT (wav, "datalength %lld", length);
651         }
652       }
653       wav->dataleft = wav->datasize = (guint64) length;
654       break;
655
656     case GST_RIFF_TAG_cue:
657       if (!gst_riff_read_skip (riff)) {
658         GST_WARNING_OBJECT (wav, "could not read skip");
659         return FALSE;
660       }
661       break;
662
663     default:
664       GST_DEBUG_OBJECT (wav, "skipping tag (%08x) %4.4s", tag, (gchar *) & tag);
665       if (!gst_riff_read_skip (riff))
666         return FALSE;
667       break;
668   }
669
670   return TRUE;
671 }
672
673 static gboolean
674 gst_wavparse_handle_seek (GstWavParse * wav)
675 {
676   GstRiffRead *riff = GST_RIFF_READ (wav);
677   GstEvent *event = NULL;
678   guint32 remaining;
679   guint8 *data;
680
681   if (!gst_bytestream_seek (riff->bs, wav->seek_offset + wav->datastart,
682           GST_SEEK_METHOD_SET))
683     return FALSE;
684
685   /* wait for discont */
686   while (!event) {
687     if (gst_bytestream_peek_bytes (riff->bs, &data, 1)) {
688       GST_WARNING ("Unexpected data after seek - this means seek failed");
689       return FALSE;
690     }
691
692     /* get the discont event and return */
693     gst_bytestream_get_status (riff->bs, &remaining, &event);
694     if (!event) {
695       GST_WARNING ("No discontinuity event after seek - seek failed");
696       return FALSE;
697     } else if (GST_EVENT_TYPE (event) != GST_EVENT_DISCONTINUOUS) {
698       GstEventType type = GST_EVENT_TYPE (event);
699
700       gst_pad_event_default (riff->sinkpad, event);
701       if (type == GST_EVENT_EOS)
702         return FALSE;
703
704       event = NULL;
705     }
706   }
707
708   wav->dataleft = wav->datasize - wav->seek_offset;
709
710   gst_event_unref (event);
711   event = gst_event_new_discontinuous (FALSE,
712       GST_FORMAT_BYTES, wav->seek_offset,
713       GST_FORMAT_TIME, GST_SECOND * wav->seek_offset / wav->bps,
714       GST_FORMAT_UNDEFINED);
715   gst_pad_event_default (wav->sinkpad, event);
716
717   return TRUE;
718 }
719
720 #define MAX_BUFFER_SIZE 4096
721
722 static void
723 gst_wavparse_loop (GstElement * element)
724 {
725   GstWavParse *wav = GST_WAVPARSE (element);
726   GstRiffRead *riff = GST_RIFF_READ (wav);
727
728   if (wav->state == GST_WAVPARSE_DATA) {
729     /* seek handling */
730     if (wav->seek_pending) {
731       gst_wavparse_handle_seek (wav);
732       wav->seek_pending = FALSE;
733     }
734
735     if (wav->dataleft > 0) {
736       guint32 got_bytes, desired;
737       GstBuffer *buf = NULL;
738
739       desired = MIN (wav->dataleft, MAX_BUFFER_SIZE);
740       if (!(buf = gst_riff_read_element_data (riff, desired, &got_bytes))) {
741         GST_WARNING_OBJECT (wav, "trying to read %d bytes failed", desired);
742         return;
743       }
744       GST_DEBUG_OBJECT (wav, "read %d bytes, got %d bytes", desired, got_bytes);
745
746       GST_BUFFER_TIMESTAMP (buf) = GST_SECOND *
747           (wav->datasize - wav->dataleft) / wav->bps;
748       GST_BUFFER_DURATION (buf) = GST_SECOND * got_bytes / wav->bps;
749
750       gst_pad_push (wav->srcpad, GST_DATA (buf));
751
752       wav->byteoffset += got_bytes;
753       if (got_bytes < wav->dataleft) {
754         wav->dataleft -= got_bytes;
755         return;
756       } else {
757         wav->dataleft = 0;
758         wav->state = GST_WAVPARSE_OTHER;
759       }
760     } else {
761       wav->state = GST_WAVPARSE_OTHER;
762     }
763   }
764
765   switch (wav->state) {
766     case GST_WAVPARSE_START:
767       if (!gst_wavparse_stream_init (wav)) {
768         return;
769       }
770
771       wav->state = GST_WAVPARSE_FMT;
772       /* fall-through */
773
774     case GST_WAVPARSE_FMT:
775       if (!gst_wavparse_fmt (wav)) {
776         return;
777       }
778
779       wav->state = GST_WAVPARSE_OTHER;
780       /* fall-through */
781
782     case GST_WAVPARSE_OTHER:
783       if (!gst_wavparse_other (wav)) {
784         return;
785       }
786
787       break;
788
789     case GST_WAVPARSE_DATA:
790
791     default:
792       g_assert_not_reached ();
793   }
794 }
795
796 /* convert and query stuff */
797 static const GstFormat *
798 gst_wavparse_get_formats (GstPad * pad)
799 {
800   static GstFormat formats[] = {
801     GST_FORMAT_TIME,
802     GST_FORMAT_BYTES,
803     GST_FORMAT_DEFAULT,         /* a "frame", ie a set of samples per Hz */
804     0
805   };
806
807   return formats;
808 }
809
810 static gboolean
811 gst_wavparse_pad_convert (GstPad * pad,
812     GstFormat src_format, gint64 src_value,
813     GstFormat * dest_format, gint64 * dest_value)
814 {
815   guint bytes_per_sample, byterate;
816   GstWavParse *wavparse;
817
818   wavparse = GST_WAVPARSE (gst_pad_get_parent (pad));
819
820   bytes_per_sample = wavparse->channels * wavparse->width / 8;
821   if (bytes_per_sample == 0) {
822     GST_DEBUG ("bytes_per_sample 0, probably an mp3 - channels %d, width %d",
823         wavparse->channels, wavparse->width);
824     return FALSE;
825   }
826   byterate = wavparse->bps;
827   if (byterate == 0) {
828     g_warning ("byterate is 0, internal error\n");
829     return FALSE;
830   }
831   GST_DEBUG ("bytes per sample: %d", bytes_per_sample);
832
833   switch (src_format) {
834     case GST_FORMAT_BYTES:
835       switch (*dest_format) {
836         case GST_FORMAT_DEFAULT:
837           *dest_value = src_value / bytes_per_sample;
838           break;
839         case GST_FORMAT_TIME:
840           *dest_value = src_value * GST_SECOND / byterate;
841           break;
842         default:
843           return FALSE;
844       }
845       *dest_value -= *dest_value % bytes_per_sample;
846       break;
847
848     case GST_FORMAT_DEFAULT:
849       switch (*dest_format) {
850         case GST_FORMAT_BYTES:
851           *dest_value = src_value * bytes_per_sample;
852           break;
853         case GST_FORMAT_TIME:
854           *dest_value = src_value * GST_SECOND / wavparse->rate;
855           break;
856         default:
857           return FALSE;
858       }
859       break;
860
861     case GST_FORMAT_TIME:
862       switch (*dest_format) {
863         case GST_FORMAT_BYTES:
864           /* make sure we end up on a sample boundary */
865           *dest_value =
866               (src_value * wavparse->rate / GST_SECOND) * wavparse->blockalign;
867           break;
868         case GST_FORMAT_DEFAULT:
869           *dest_value = src_value * wavparse->rate / GST_SECOND;
870           break;
871         default:
872           return FALSE;
873       }
874       break;
875
876     default:
877       return FALSE;
878   }
879
880   return TRUE;
881 }
882
883 static const GstQueryType *
884 gst_wavparse_get_query_types (GstPad * pad)
885 {
886   static const GstQueryType types[] = {
887     GST_QUERY_TOTAL,
888     GST_QUERY_POSITION,
889     0
890   };
891
892   return types;
893 }
894
895 /* handle queries for location and length in requested format */
896 static gboolean
897 gst_wavparse_pad_query (GstPad * pad, GstQueryType type,
898     GstFormat * format, gint64 * value)
899 {
900   gint64 bytevalue;
901   GstWavParse *wav = GST_WAVPARSE (gst_pad_get_parent (pad));
902
903   /* only if we know */
904   if (wav->state != GST_WAVPARSE_DATA)
905     return FALSE;
906
907   switch (type) {
908     case GST_QUERY_POSITION:
909       bytevalue = wav->datasize - wav->dataleft;
910       break;
911     case GST_QUERY_TOTAL:
912       bytevalue = wav->datasize;
913       break;
914     default:
915       return FALSE;
916   }
917
918   if (*format == GST_FORMAT_BYTES) {
919     *value = bytevalue;
920     return TRUE;
921   }
922
923   return gst_pad_convert (wav->sinkpad, GST_FORMAT_BYTES,
924       bytevalue, format, value);
925 }
926
927 static const GstEventMask *
928 gst_wavparse_get_event_masks (GstPad * pad)
929 {
930   static const GstEventMask gst_wavparse_src_event_masks[] = {
931     {GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH},
932     {0,}
933   };
934
935   return gst_wavparse_src_event_masks;
936 }
937
938 static gboolean
939 gst_wavparse_srcpad_event (GstPad * pad, GstEvent * event)
940 {
941   GstWavParse *wavparse = GST_WAVPARSE (GST_PAD_PARENT (pad));
942   gboolean res = FALSE;
943
944   GST_DEBUG ("event %d", GST_EVENT_TYPE (event));
945
946   switch (GST_EVENT_TYPE (event)) {
947     case GST_EVENT_SEEK:
948     {
949       gint64 byteoffset;
950       GstFormat format;
951
952       /* bring format to samples for the peer element, */
953       format = GST_FORMAT_BYTES;
954       res = gst_pad_convert (pad,
955           GST_EVENT_SEEK_FORMAT (event),
956           GST_EVENT_SEEK_OFFSET (event), &format, &byteoffset);
957
958       if (res) {
959         /* ok, seek worked, update our state */
960         wavparse->seek_offset = byteoffset;
961         wavparse->seek_pending = TRUE;
962       }
963       break;
964     }
965     default:
966       break;
967   }
968
969   gst_event_unref (event);
970
971   return res;
972 }
973
974 static GstElementStateReturn
975 gst_wavparse_change_state (GstElement * element)
976 {
977   GstWavParse *wav = GST_WAVPARSE (element);
978
979   switch (GST_STATE_TRANSITION (element)) {
980     case GST_STATE_NULL_TO_READY:
981       break;
982
983     case GST_STATE_READY_TO_PAUSED:
984       wav->state = GST_WAVPARSE_START;
985       break;
986
987     case GST_STATE_PAUSED_TO_PLAYING:
988       break;
989
990     case GST_STATE_PLAYING_TO_PAUSED:
991       break;
992
993     case GST_STATE_PAUSED_TO_READY:
994       gst_wavparse_destroy_sourcepad (wav);
995       wav->state = GST_WAVPARSE_START;
996
997       wav->width = 0;
998       wav->depth = 0;
999       wav->rate = 0;
1000       wav->channels = 0;
1001
1002       wav->seek_pending = FALSE;
1003       wav->seek_offset = 0;
1004       break;
1005
1006     case GST_STATE_READY_TO_NULL:
1007       break;
1008   }
1009
1010   if (GST_ELEMENT_CLASS (parent_class)->change_state)
1011     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
1012
1013   return GST_STATE_SUCCESS;
1014 }
1015
1016 static gboolean
1017 plugin_init (GstPlugin * plugin)
1018 {
1019   if (!gst_library_load ("riff")) {
1020     return FALSE;
1021   }
1022
1023   return gst_element_register (plugin, "wavparse", GST_RANK_PRIMARY,
1024       GST_TYPE_WAVPARSE);
1025 }
1026
1027 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1028     GST_VERSION_MINOR,
1029     "wavparse",
1030     "Parse a .wav file into raw audio",
1031     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN)