4bd772a358f0093fcfbfb28ddf5bc56db7b22d65
[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 #ifndef G_MAXUINT32
32 #define G_MAXUINT32 0xffffffff
33 #endif
34
35 GST_DEBUG_CATEGORY (wavparse_debug);
36 #define GST_CAT_DEFAULT (wavparse_debug)
37
38 static void gst_wavparse_base_init (gpointer g_class);
39 static void gst_wavparse_class_init (GstWavParseClass * klass);
40 static void gst_wavparse_init (GstWavParse * wavparse);
41
42 static gboolean gst_wavparse_sink_activate (GstPad * sinkpad);
43 static gboolean gst_wavparse_sink_activate_pull (GstPad * sinkpad,
44     gboolean active);
45 static GstStateChangeReturn gst_wavparse_change_state (GstElement * element,
46     GstStateChange transition);
47
48 static gboolean gst_wavparse_pad_query (GstPad * pad, GstQuery * query);
49 static const GstQueryType *gst_wavparse_get_query_types (GstPad * pad);
50 static gboolean gst_wavparse_pad_convert (GstPad * pad,
51     GstFormat src_format,
52     gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
53
54 static void gst_wavparse_loop (GstPad * pad);
55 static gboolean gst_wavparse_srcpad_event (GstPad * pad, GstEvent * event);
56 static void gst_wavparse_get_property (GObject * object, guint prop_id,
57     GValue * value, GParamSpec * pspec);
58
59 static GstStaticPadTemplate sink_template_factory =
60 GST_STATIC_PAD_TEMPLATE ("wavparse_sink",
61     GST_PAD_SINK,
62     GST_PAD_ALWAYS,
63     GST_STATIC_CAPS ("audio/x-wav")
64     );
65
66 static GstStaticPadTemplate src_template_factory =
67     GST_STATIC_PAD_TEMPLATE ("wavparse_src",
68     GST_PAD_SRC,
69     GST_PAD_SOMETIMES,          /* FIXME: spider */
70     GST_STATIC_CAPS ("audio/x-raw-int, "
71         "endianness = (int) little_endian, "
72         "signed = (boolean) { true, false }, "
73         "width = (int) { 8, 16, 24, 32 }, "
74         "depth = (int) { 8, 16, 24, 32 }, "
75         "rate = (int) [ 8000, 48000 ], "
76         "channels = (int) [ 1, 2 ]; "
77         "audio/mpeg, "
78         "mpegversion = (int) 1, "
79         "layer = (int) [ 1, 3 ], "
80         "rate = (int) [ 8000, 48000 ], "
81         "channels = (int) [ 1, 2 ]; "
82         "audio/x-alaw, "
83         "rate = (int) [ 8000, 48000 ], "
84         "channels = (int) [ 1, 2 ]; "
85         "audio/x-mulaw, "
86         "rate = (int) [ 8000, 48000 ], " "channels = (int) [ 1, 2 ];"
87         "audio/x-adpcm, "
88         "layout = (string) microsoft, "
89         "block_align = (int) [ 1, 8192 ], "
90         "rate = (int) [ 8000, 48000 ], "
91         "channels = (int) [ 1, 2 ]; "
92         "audio/x-adpcm, "
93         "layout = (string) dvi, "
94         "block_align = (int) [ 1, 8192 ], "
95         "rate = (int) [ 8000, 48000 ], " "channels = (int) [ 1, 2 ];"
96         "audio/x-vnd.sony.atrac3")
97     );
98
99 /* WavParse signals and args */
100 enum
101 {
102   /* FILL ME */
103   LAST_SIGNAL
104 };
105
106 enum
107 {
108   PROP_0
109 };
110
111 static GstElementClass *parent_class = NULL;
112
113 /*static guint gst_wavparse_signals[LAST_SIGNAL] = { 0 }; */
114
115 GType
116 gst_wavparse_get_type (void)
117 {
118   static GType wavparse_type = 0;
119
120   if (!wavparse_type) {
121     static const GTypeInfo wavparse_info = {
122       sizeof (GstWavParseClass),
123       gst_wavparse_base_init,
124       NULL,
125       (GClassInitFunc) gst_wavparse_class_init,
126       NULL,
127       NULL,
128       sizeof (GstWavParse),
129       0,
130       (GInstanceInitFunc) gst_wavparse_init,
131     };
132
133     wavparse_type =
134         g_type_register_static (GST_TYPE_ELEMENT, "GstWavParse",
135         &wavparse_info, 0);
136   }
137   return wavparse_type;
138 }
139
140
141 static void
142 gst_wavparse_base_init (gpointer g_class)
143 {
144   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
145   static GstElementDetails gst_wavparse_details =
146       GST_ELEMENT_DETAILS (".wav demuxer",
147       "Codec/Demuxer/Audio",
148       "Parse a .wav file into raw audio",
149       "Erik Walthinsen <omega@cse.ogi.edu>");
150
151   gst_element_class_set_details (element_class, &gst_wavparse_details);
152
153   /* register src pads */
154   gst_element_class_add_pad_template (element_class,
155       gst_static_pad_template_get (&sink_template_factory));
156   gst_element_class_add_pad_template (element_class,
157       gst_static_pad_template_get (&src_template_factory));
158 }
159
160 static void
161 gst_wavparse_class_init (GstWavParseClass * klass)
162 {
163   GstElementClass *gstelement_class;
164   GObjectClass *object_class;
165
166   gstelement_class = (GstElementClass *) klass;
167   object_class = (GObjectClass *) klass;
168
169   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
170
171   object_class->get_property = gst_wavparse_get_property;
172   gstelement_class->change_state = gst_wavparse_change_state;
173
174   GST_DEBUG_CATEGORY_INIT (wavparse_debug, "wavparse", 0, "WAV parser");
175 }
176
177 static void
178 gst_wavparse_reset (GstWavParse * wavparse)
179 {
180   wavparse->state = GST_WAVPARSE_START;
181
182   /* These will all be set correctly in the fmt chunk */
183   wavparse->depth = 0;
184   wavparse->rate = 0;
185   wavparse->width = 0;
186   wavparse->channels = 0;
187   wavparse->blockalign = 0;
188   wavparse->bps = 0;
189   wavparse->dataleft = 0;
190   wavparse->datasize = 0;
191   wavparse->datastart = 0;
192
193   if (wavparse->seek_event)
194     gst_event_unref (wavparse->seek_event);
195   wavparse->seek_event = NULL;
196   wavparse->seek_pending = FALSE;
197
198   wavparse->segment_rate = 1.0;
199   wavparse->segment_start = -1;
200   wavparse->segment_stop = -1;
201 }
202
203 static void
204 gst_wavparse_init (GstWavParse * wavparse)
205 {
206   /* sink */
207   wavparse->sinkpad =
208       gst_pad_new_from_template (gst_static_pad_template_get
209       (&sink_template_factory), "sink");
210   gst_element_add_pad (GST_ELEMENT (wavparse), wavparse->sinkpad);
211   gst_pad_set_activate_function (wavparse->sinkpad, gst_wavparse_sink_activate);
212   gst_pad_set_activatepull_function (wavparse->sinkpad,
213       gst_wavparse_sink_activate_pull);
214   gst_wavparse_reset (wavparse);
215 }
216
217 static void
218 gst_wavparse_destroy_sourcepad (GstWavParse * wavparse)
219 {
220   if (wavparse->srcpad) {
221     gst_element_remove_pad (GST_ELEMENT (wavparse), wavparse->srcpad);
222     wavparse->srcpad = NULL;
223   }
224 }
225
226 static void
227 gst_wavparse_create_sourcepad (GstWavParse * wavparse)
228 {
229   gst_wavparse_destroy_sourcepad (wavparse);
230
231   /* source */
232   wavparse->srcpad =
233       gst_pad_new_from_template (gst_static_pad_template_get
234       (&src_template_factory), "src");
235   gst_pad_use_fixed_caps (wavparse->srcpad);
236   gst_pad_set_query_type_function (wavparse->srcpad,
237       gst_wavparse_get_query_types);
238   gst_pad_set_query_function (wavparse->srcpad, gst_wavparse_pad_query);
239   gst_pad_set_event_function (wavparse->srcpad, gst_wavparse_srcpad_event);
240 }
241
242 static void
243 gst_wavparse_get_property (GObject * object,
244     guint prop_id, GValue * value, GParamSpec * pspec)
245 {
246   GstWavParse *wavparse;
247
248   wavparse = GST_WAVPARSE (object);
249
250   switch (prop_id) {
251     default:
252       break;
253   }
254 }
255
256 #if 0
257 static void
258 gst_wavparse_parse_adtl (GstWavParse * wavparse, int len)
259 {
260   guint32 got_bytes;
261   GstByteStream *bs = wavparse->bs;
262   gst_riff_chunk *temp_chunk, chunk;
263   guint8 *tempdata;
264   struct _gst_riff_labl labl, *temp_labl;
265   struct _gst_riff_ltxt ltxt, *temp_ltxt;
266   struct _gst_riff_note note, *temp_note;
267   char *label_name;
268   GstProps *props;
269   GstPropsEntry *entry;
270   GstCaps *new_caps;
271   GList *caps = NULL;
272
273   props = wavparse->metadata->properties;
274
275   while (len > 0) {
276     got_bytes =
277         gst_bytestream_peek_bytes (bs, &tempdata, sizeof (gst_riff_chunk));
278     if (got_bytes != sizeof (gst_riff_chunk)) {
279       return;
280     }
281     temp_chunk = (gst_riff_chunk *) tempdata;
282
283     chunk.id = GUINT32_FROM_LE (temp_chunk->id);
284     chunk.size = GUINT32_FROM_LE (temp_chunk->size);
285
286     if (chunk.size == 0) {
287       gst_bytestream_flush (bs, sizeof (gst_riff_chunk));
288       len -= sizeof (gst_riff_chunk);
289       continue;
290     }
291
292     switch (chunk.id) {
293       case GST_RIFF_adtl_labl:
294         got_bytes =
295             gst_bytestream_peek_bytes (bs, &tempdata,
296             sizeof (struct _gst_riff_labl));
297         if (got_bytes != sizeof (struct _gst_riff_labl)) {
298           return;
299         }
300
301         temp_labl = (struct _gst_riff_labl *) tempdata;
302         labl.id = GUINT32_FROM_LE (temp_labl->id);
303         labl.size = GUINT32_FROM_LE (temp_labl->size);
304         labl.identifier = GUINT32_FROM_LE (temp_labl->identifier);
305
306         gst_bytestream_flush (bs, sizeof (struct _gst_riff_labl));
307         len -= sizeof (struct _gst_riff_labl);
308
309         got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, labl.size - 4);
310         if (got_bytes != labl.size - 4) {
311           return;
312         }
313
314         label_name = (char *) tempdata;
315
316         gst_bytestream_flush (bs, ((labl.size - 4) + 1) & ~1);
317         len -= (((labl.size - 4) + 1) & ~1);
318
319         new_caps = gst_caps_new ("label",
320             "application/x-gst-metadata",
321             gst_props_new ("identifier", G_TYPE_INT (labl.identifier),
322                 "name", G_TYPE_STRING (label_name), NULL));
323
324         if (gst_props_get (props, "labels", &caps, NULL)) {
325           caps = g_list_append (caps, new_caps);
326         } else {
327           caps = g_list_append (NULL, new_caps);
328
329           entry = gst_props_entry_new ("labels", GST_PROPS_GLIST (caps));
330           gst_props_add_entry (props, entry);
331         }
332
333         break;
334
335       case GST_RIFF_adtl_ltxt:
336         got_bytes =
337             gst_bytestream_peek_bytes (bs, &tempdata,
338             sizeof (struct _gst_riff_ltxt));
339         if (got_bytes != sizeof (struct _gst_riff_ltxt)) {
340           return;
341         }
342
343         temp_ltxt = (struct _gst_riff_ltxt *) tempdata;
344         ltxt.id = GUINT32_FROM_LE (temp_ltxt->id);
345         ltxt.size = GUINT32_FROM_LE (temp_ltxt->size);
346         ltxt.identifier = GUINT32_FROM_LE (temp_ltxt->identifier);
347         ltxt.length = GUINT32_FROM_LE (temp_ltxt->length);
348         ltxt.purpose = GUINT32_FROM_LE (temp_ltxt->purpose);
349         ltxt.country = GUINT16_FROM_LE (temp_ltxt->country);
350         ltxt.language = GUINT16_FROM_LE (temp_ltxt->language);
351         ltxt.dialect = GUINT16_FROM_LE (temp_ltxt->dialect);
352         ltxt.codepage = GUINT16_FROM_LE (temp_ltxt->codepage);
353
354         gst_bytestream_flush (bs, sizeof (struct _gst_riff_ltxt));
355         len -= sizeof (struct _gst_riff_ltxt);
356
357         if (ltxt.size - 20 > 0) {
358           got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, ltxt.size - 20);
359           if (got_bytes != ltxt.size - 20) {
360             return;
361           }
362
363           gst_bytestream_flush (bs, ((ltxt.size - 20) + 1) & ~1);
364           len -= (((ltxt.size - 20) + 1) & ~1);
365
366           label_name = (char *) tempdata;
367         } else {
368           label_name = "";
369         }
370
371         new_caps = gst_caps_new ("ltxt",
372             "application/x-gst-metadata",
373             gst_props_new ("identifier", G_TYPE_INT (ltxt.identifier),
374                 "name", G_TYPE_STRING (label_name),
375                 "length", G_TYPE_INT (ltxt.length), NULL));
376
377         if (gst_props_get (props, "ltxts", &caps, NULL)) {
378           caps = g_list_append (caps, new_caps);
379         } else {
380           caps = g_list_append (NULL, new_caps);
381
382           entry = gst_props_entry_new ("ltxts", GST_PROPS_GLIST (caps));
383           gst_props_add_entry (props, entry);
384         }
385
386         break;
387
388       case GST_RIFF_adtl_note:
389         got_bytes =
390             gst_bytestream_peek_bytes (bs, &tempdata,
391             sizeof (struct _gst_riff_note));
392         if (got_bytes != sizeof (struct _gst_riff_note)) {
393           return;
394         }
395
396         temp_note = (struct _gst_riff_note *) tempdata;
397         note.id = GUINT32_FROM_LE (temp_note->id);
398         note.size = GUINT32_FROM_LE (temp_note->size);
399         note.identifier = GUINT32_FROM_LE (temp_note->identifier);
400
401         gst_bytestream_flush (bs, sizeof (struct _gst_riff_note));
402         len -= sizeof (struct _gst_riff_note);
403
404         got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, note.size - 4);
405         if (got_bytes != note.size - 4) {
406           return;
407         }
408
409         gst_bytestream_flush (bs, ((note.size - 4) + 1) & ~1);
410         len -= (((note.size - 4) + 1) & ~1);
411
412         label_name = (char *) tempdata;
413
414         new_caps = gst_caps_new ("note",
415             "application/x-gst-metadata",
416             gst_props_new ("identifier", G_TYPE_INT (note.identifier),
417                 "name", G_TYPE_STRING (label_name), NULL));
418
419         if (gst_props_get (props, "notes", &caps, NULL)) {
420           caps = g_list_append (caps, new_caps);
421         } else {
422           caps = g_list_append (NULL, new_caps);
423
424           entry = gst_props_entry_new ("notes", GST_PROPS_GLIST (caps));
425           gst_props_add_entry (props, entry);
426         }
427
428         break;
429
430       default:
431         g_print ("Unknown chunk: " GST_FOURCC_FORMAT "\n",
432             GST_FOURCC_ARGS (chunk.id));
433         return;
434     }
435   }
436
437   g_object_notify (G_OBJECT (wavparse), "metadata");
438 }
439 #endif
440
441 #if 0
442 static void
443 gst_wavparse_parse_cues (GstWavParse * wavparse, int len)
444 {
445   guint32 got_bytes;
446   GstByteStream *bs = wavparse->bs;
447   struct _gst_riff_cue *temp_cue, cue;
448   struct _gst_riff_cuepoints *points;
449   guint8 *tempdata;
450   int i;
451   GList *cues = NULL;
452   GstPropsEntry *entry;
453
454   while (len > 0) {
455     int required;
456
457     got_bytes =
458         gst_bytestream_peek_bytes (bs, &tempdata,
459         sizeof (struct _gst_riff_cue));
460     temp_cue = (struct _gst_riff_cue *) tempdata;
461
462     /* fixup for our big endian friends */
463     cue.id = GUINT32_FROM_LE (temp_cue->id);
464     cue.size = GUINT32_FROM_LE (temp_cue->size);
465     cue.cuepoints = GUINT32_FROM_LE (temp_cue->cuepoints);
466
467     gst_bytestream_flush (bs, sizeof (struct _gst_riff_cue));
468     if (got_bytes != sizeof (struct _gst_riff_cue)) {
469       return;
470     }
471
472     len -= sizeof (struct _gst_riff_cue);
473
474     /* -4 because cue.size contains the cuepoints size
475        and we've already flushed that out of the system */
476     required = cue.size - 4;
477     got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, required);
478     gst_bytestream_flush (bs, ((required) + 1) & ~1);
479     if (got_bytes != required) {
480       return;
481     }
482
483     len -= (((cue.size - 4) + 1) & ~1);
484
485     /* now we have an array of struct _gst_riff_cuepoints in tempdata */
486     points = (struct _gst_riff_cuepoints *) tempdata;
487
488     for (i = 0; i < cue.cuepoints; i++) {
489       GstCaps *caps;
490
491       caps = gst_caps_new ("cues",
492           "application/x-gst-metadata",
493           gst_props_new ("identifier", G_TYPE_INT (points[i].identifier),
494               "position", G_TYPE_INT (points[i].offset), NULL));
495       cues = g_list_append (cues, caps);
496     }
497
498     entry = gst_props_entry_new ("cues", GST_PROPS_GLIST (cues));
499     gst_props_add_entry (wavparse->metadata->properties, entry);
500   }
501
502   g_object_notify (G_OBJECT (wavparse), "metadata");
503 }
504 #endif
505
506 static gboolean
507 gst_wavparse_parse_file_header (GstElement * element, GstBuffer * buf)
508 {
509   guint32 doctype;
510
511   if (!gst_riff_parse_file_header (element, buf, &doctype))
512     return FALSE;
513
514   if (doctype != GST_RIFF_RIFF_WAVE)
515     goto not_wav;
516
517   return TRUE;
518
519 not_wav:
520   {
521     GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL),
522         ("File is not an WAVE file: " GST_FOURCC_FORMAT,
523             GST_FOURCC_ARGS (doctype)));
524     return FALSE;
525   }
526 }
527
528 static GstFlowReturn
529 gst_wavparse_stream_init (GstWavParse * wav)
530 {
531   GstFlowReturn res;
532   GstBuffer *buf = NULL;
533
534   if ((res = gst_pad_pull_range (wav->sinkpad,
535               wav->offset, 12, &buf)) != GST_FLOW_OK)
536     return res;
537
538   else if (!gst_wavparse_parse_file_header (GST_ELEMENT (wav), buf))
539     return GST_FLOW_ERROR;
540
541   wav->offset += 12;
542
543   return GST_FLOW_OK;
544 }
545
546 #if 0
547 /* Read 'fmt ' header */
548 static gboolean
549 gst_wavparse_fmt (GstWavParse * wav)
550 {
551   gst_riff_strf_auds *header = NULL;
552   GstCaps *caps;
553
554   if (!gst_riff_read_strf_auds (wav, &header)) {
555     g_warning ("Not fmt");
556     return FALSE;
557   }
558
559   wav->format = header->format;
560   wav->rate = header->rate;
561   wav->channels = header->channels;
562   if (wav->channels == 0) {
563     GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL),
564         ("Stream claims to contain zero channels - invalid data"));
565     g_free (header);
566     return FALSE;
567   }
568   wav->blockalign = header->blockalign;
569   wav->width = (header->blockalign * 8) / header->channels;
570   wav->depth = header->size;
571   wav->bps = header->av_bps;
572   if (wav->bps <= 0) {
573     GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL),
574         ("Stream claims to bitrate of <= zero - invalid data"));
575     g_free (header);
576     return FALSE;
577   }
578
579   /* Note: gst_riff_create_audio_caps might nedd to fix values in
580    * the header header depending on the format, so call it first */
581   caps = gst_riff_create_audio_caps (header->format, NULL, header, NULL);
582
583   g_free (header);
584
585   if (caps) {
586     gst_wavparse_create_sourcepad (wav);
587     gst_pad_use_fixed_caps (wav->srcpad);
588     gst_pad_set_active (wav->srcpad, TRUE);
589     gst_pad_set_caps (wav->srcpad, caps);
590     gst_caps_free (caps);
591     gst_element_add_pad (GST_ELEMENT (wav), wav->srcpad);
592     gst_element_no_more_pads (GST_ELEMENT (wav));
593     GST_DEBUG ("frequency %d, channels %d", wav->rate, wav->channels);
594   } else {
595     GST_ELEMENT_ERROR (wav, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
596     return FALSE;
597   }
598
599   return TRUE;
600 }
601
602 static gboolean
603 gst_wavparse_other (GstWavParse * wav)
604 {
605   guint32 tag, length;
606
607   if (!gst_riff_peek_head (wav, &tag, &length, NULL)) {
608     GST_WARNING_OBJECT (wav, "could not peek head");
609     return FALSE;
610   }
611   GST_DEBUG_OBJECT (wav, "got tag (%08x) %4.4s, length %d", tag,
612       (gchar *) & tag, length);
613
614   switch (tag) {
615     case GST_RIFF_TAG_LIST:
616       if (!(tag = gst_riff_peek_list (wav))) {
617         GST_WARNING_OBJECT (wav, "could not peek list");
618         return FALSE;
619       }
620
621       switch (tag) {
622         case GST_RIFF_LIST_INFO:
623           if (!gst_riff_read_list (wav, &tag) || !gst_riff_read_info (wav)) {
624             GST_WARNING_OBJECT (wav, "could not read list");
625             return FALSE;
626           }
627           break;
628
629         case GST_RIFF_LIST_adtl:
630           if (!gst_riff_read_skip (wav)) {
631             GST_WARNING_OBJECT (wav, "could not read skip");
632             return FALSE;
633           }
634           break;
635
636         default:
637           GST_DEBUG_OBJECT (wav, "skipping tag (%08x) %4.4s", tag,
638               (gchar *) & tag);
639           if (!gst_riff_read_skip (wav)) {
640             GST_WARNING_OBJECT (wav, "could not read skip");
641             return FALSE;
642           }
643           break;
644       }
645
646       break;
647
648     case GST_RIFF_TAG_data:
649       if (!gst_bytestream_flush (wav->bs, 8)) {
650         GST_WARNING_OBJECT (wav, "could not flush 8 bytes");
651         return FALSE;
652       }
653
654       GST_DEBUG_OBJECT (wav, "switching to data mode");
655       wav->state = GST_WAVPARSE_DATA;
656       wav->datastart = gst_bytestream_tell (wav->bs);
657       if (length == 0) {
658         guint64 file_length;
659
660         /* length is 0, data probably stretches to the end
661          * of file */
662         GST_DEBUG_OBJECT (wav, "length is 0 trying to find length");
663         /* get length of file */
664         file_length = gst_bytestream_length (wav->bs);
665         if (file_length == -1) {
666           GST_DEBUG_OBJECT (wav,
667               "could not get file length, assuming data to eof");
668           /* could not get length, assuming till eof */
669           length = G_MAXUINT32;
670         }
671         if (file_length > G_MAXUINT32) {
672           GST_DEBUG_OBJECT (wav, "file length %lld, clipping to 32 bits");
673           /* could not get length, assuming till eof */
674           length = G_MAXUINT32;
675         } else {
676           GST_DEBUG_OBJECT (wav, "file length %lld, datalength",
677               file_length, length);
678           /* substract offset of datastart from length */
679           length = file_length - wav->datastart;
680           GST_DEBUG_OBJECT (wav, "datalength %lld", length);
681         }
682       }
683       wav->dataleft = wav->datasize = (guint64) length;
684       break;
685
686     case GST_RIFF_TAG_cue:
687       if (!gst_riff_read_skip (wav)) {
688         GST_WARNING_OBJECT (wav, "could not read skip");
689         return FALSE;
690       }
691       break;
692
693     default:
694       GST_DEBUG_OBJECT (wav, "skipping tag (%08x) %4.4s", tag, (gchar *) & tag);
695       if (!gst_riff_read_skip (wav))
696         return FALSE;
697       break;
698   }
699
700   return TRUE;
701 }
702 #endif
703
704 static gboolean
705 gst_wavparse_handle_seek (GstWavParse * wav, gboolean update)
706 {
707   GstClockTime start_time, stop_time;
708   gboolean flush;
709
710   flush = wav->segment_flags & GST_SEEK_FLAG_FLUSH;
711
712   if (flush)
713     gst_pad_push_event (wav->srcpad, gst_event_new_flush_start ());
714   else
715     gst_pad_pause_task (wav->sinkpad);
716
717   GST_STREAM_LOCK (wav->sinkpad);
718
719   if (update) {
720     wav->offset = wav->segment_start + wav->datastart;
721     wav->dataleft = wav->segment_stop - wav->segment_start;
722     start_time = GST_SECOND * wav->segment_start / wav->bps;
723   } else {
724     start_time = (wav->offset - wav->datastart) * GST_SECOND / wav->bps;
725   }
726   stop_time = GST_SECOND * wav->segment_stop / wav->bps;
727
728   GST_DEBUG ("seek: offset %" G_GUINT64_FORMAT ", len %" G_GUINT64_FORMAT
729       ", segment %" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT,
730       wav->offset, wav->dataleft, GST_TIME_ARGS (start_time),
731       GST_TIME_ARGS (stop_time));
732
733   wav->seek_event = gst_event_new_newsegment (!update, wav->segment_rate,
734       GST_FORMAT_TIME, start_time, stop_time, start_time);
735
736   if (flush)
737     gst_pad_push_event (wav->srcpad, gst_event_new_flush_stop ());
738
739   if (wav->segment_flags & GST_SEEK_FLAG_SEGMENT) {
740     gst_element_post_message (GST_ELEMENT (wav),
741         gst_message_new_segment_start (GST_OBJECT (wav), GST_FORMAT_TIME,
742             start_time));
743   }
744
745   gst_pad_start_task (wav->sinkpad, (GstTaskFunction) gst_wavparse_loop,
746       wav->sinkpad);
747
748   GST_STREAM_UNLOCK (wav->sinkpad);
749
750   return TRUE;
751
752 }
753
754 static GstFlowReturn
755 gst_wavparse_stream_headers (GstWavParse * wav)
756 {
757   GstFlowReturn res;
758   GstBuffer *buf, *extra;
759   gst_riff_strf_auds *header = NULL;
760   guint32 tag;
761   gboolean gotdata = FALSE;
762   GstCaps *caps;
763
764   /* The header start with a 'fmt ' tag */
765   if ((res = gst_riff_read_chunk (GST_ELEMENT (wav), wav->sinkpad,
766               &wav->offset, &tag, &buf)) != GST_FLOW_OK)
767     return res;
768
769   else if (tag != GST_RIFF_TAG_fmt)
770     goto invalid_wav;
771
772   if (!(gst_riff_parse_strf_auds (GST_ELEMENT (wav), buf, &header, &extra)))
773     goto parse_header_error;
774
775   /* Note: gst_riff_create_audio_caps might nedd to fix values in
776    * the header header depending on the format, so call it first */
777   caps =
778       gst_riff_create_audio_caps (header->format, NULL, header, NULL,
779       NULL, NULL);
780
781   wav->format = header->format;
782   wav->rate = header->rate;
783   wav->channels = header->channels;
784
785   if (wav->channels == 0)
786     goto no_channels;
787
788   wav->blockalign = header->blockalign;
789   wav->width = (header->blockalign * 8) / header->channels;
790   wav->depth = header->size;
791   wav->bps = header->av_bps;
792
793   if (wav->bps <= 0)
794     goto no_bitrate;
795
796   wav->bytes_per_sample = wav->channels * wav->width / 8;
797   if (wav->bytes_per_sample <= 0)
798     goto no_bytes_per_sample;
799
800   g_free (header);
801
802   if (!caps)
803     goto unknown_format;
804
805   gst_wavparse_create_sourcepad (wav);
806   gst_pad_set_active (wav->srcpad, TRUE);
807   gst_pad_set_caps (wav->srcpad, caps);
808   gst_caps_unref (caps);
809   caps = NULL;
810
811   gst_element_add_pad (GST_ELEMENT (wav), wav->srcpad);
812   gst_element_no_more_pads (GST_ELEMENT (wav));
813
814   GST_DEBUG ("frequency %d, channels %d", wav->rate, wav->channels);
815
816   /* loop headers until we get data */
817   while (!gotdata) {
818     guint size;
819     guint32 tag;
820
821     if ((res =
822             gst_pad_pull_range (wav->sinkpad, wav->offset, 8,
823                 &buf)) != GST_FLOW_OK)
824       goto header_read_error;
825
826     /*
827        wav is a st00pid format, we don't know for sure where data starts.
828        So we have to go bit by bit until we find the 'data' header
829      */
830     tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf));
831     size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 4);
832
833     switch (tag) {
834         /* TODO : Implement the various cases */
835       case GST_RIFF_TAG_data:
836         GST_DEBUG ("Got 'data' TAG, size : %d", size);
837         gotdata = TRUE;
838         wav->offset += 8;
839         wav->datastart = wav->offset;
840         wav->datasize = size;
841         wav->dataleft = wav->datasize;
842         break;
843       default:
844         GST_DEBUG ("Ignoring tag" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag));
845         wav->offset += 8 + ((size + 1) & ~1);
846     }
847     gst_buffer_unref (buf);
848   }
849
850   GST_DEBUG ("Finished parsing headers");
851
852   wav->segment_start = 0;
853   /* FIXME, can overflow */
854   wav->segment_stop = (gint64) GST_SECOND *wav->datasize / wav->bps;
855
856   /* Initial discont */
857   wav->seek_event = gst_event_new_newsegment (FALSE, 1.0,
858       GST_FORMAT_TIME,
859       wav->segment_start, wav->segment_stop, wav->segment_start);
860
861   return GST_FLOW_OK;
862
863   /* ERROR */
864 invalid_wav:
865   {
866     GST_ELEMENT_ERROR (wav, STREAM, DEMUX, (NULL),
867         ("Invalid WAV header (no fmt at start): "
868             GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
869     return GST_FLOW_ERROR;
870   }
871 parse_header_error:
872   {
873     GST_ELEMENT_ERROR (wav, STREAM, DEMUX, (NULL),
874         ("Couldn't parse audio header"));
875     gst_buffer_unref (buf);
876     return GST_FLOW_ERROR;
877   }
878 no_channels:
879   {
880     GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL),
881         ("Stream claims to contain no channels - invalid data"));
882     g_free (header);
883     return GST_FLOW_ERROR;
884   }
885 no_bitrate:
886   {
887     GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL),
888         ("Stream claims to have a bitrate of <= zero - invalid data"));
889     g_free (header);
890     return GST_FLOW_ERROR;
891   }
892 no_bytes_per_sample:
893   {
894     GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL),
895         ("could not caluclate bytes per sample - invalid data"));
896     g_free (header);
897     return GST_FLOW_ERROR;
898   }
899 unknown_format:
900   {
901     GST_ELEMENT_ERROR (wav, STREAM, TYPE_NOT_FOUND, (NULL),
902         ("No caps found for format 0x%x, %d channels, %d Hz",
903             wav->format, wav->channels, wav->rate));
904     return GST_FLOW_ERROR;
905   }
906 header_read_error:
907   {
908     GST_ELEMENT_ERROR (wav, STREAM, DEMUX, (NULL), ("Couldn't read in header"));
909     return GST_FLOW_ERROR;
910   }
911 }
912
913 #define MAX_BUFFER_SIZE 4096
914
915 static GstFlowReturn
916 gst_wavparse_stream_data (GstWavParse * wav)
917 {
918   GstBuffer *buf = NULL;
919   GstFlowReturn res = GST_FLOW_OK;
920   guint64 desired, obtained;
921
922   GST_DEBUG ("offset : %lld , dataleft : %lld", wav->offset, wav->dataleft);
923
924   /* Get the next n bytes and output them */
925   if (wav->dataleft == 0)
926     goto found_eos;
927
928   desired = MIN (wav->dataleft, MAX_BUFFER_SIZE * ABS (wav->segment_rate));
929   if (desired >= wav->blockalign && wav->blockalign > 0)
930     desired -= (desired % wav->blockalign);
931
932   GST_DEBUG ("Fetching %lld bytes of data from the sinkpad.", desired);
933
934   if ((res = gst_pad_pull_range (wav->sinkpad, wav->offset,
935               desired, &buf)) != GST_FLOW_OK)
936     goto pull_error;
937
938   obtained = GST_BUFFER_SIZE (buf);
939   GST_BUFFER_OFFSET (buf) =
940       (wav->offset - wav->datastart) / wav->bytes_per_sample;
941   GST_BUFFER_TIMESTAMP (buf) =
942       GST_SECOND * (wav->offset - wav->datastart) / wav->bps;
943   GST_BUFFER_DURATION (buf) = 1 + GST_SECOND * obtained / wav->bps;
944   gst_buffer_set_caps (buf, GST_PAD_CAPS (wav->srcpad));
945
946   GST_DEBUG ("Got buffer. timestamp:%" GST_TIME_FORMAT " , duration:%"
947       GST_TIME_FORMAT ", size:%u",
948       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
949       GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_SIZE (buf));
950
951   if ((res = gst_pad_push (wav->srcpad, buf)) != GST_FLOW_OK)
952     goto push_error;
953
954   if (obtained < wav->dataleft) {
955     wav->dataleft -= obtained;
956     wav->offset += obtained;
957   } else {
958     wav->dataleft = 0;
959   }
960   return res;
961
962   /* ERROR */
963 found_eos:
964   {
965     GST_DEBUG ("found EOS");
966     if (wav->segment_flags & GST_SEEK_FLAG_SEGMENT) {
967       GstClockTime stop_time;
968
969       stop_time = GST_SECOND * wav->segment_stop / wav->bps;
970
971       gst_element_post_message (GST_ELEMENT (wav),
972           gst_message_new_segment_done (GST_OBJECT (wav), GST_FORMAT_TIME,
973               stop_time));
974     } else {
975       gst_pad_push_event (wav->srcpad, gst_event_new_eos ());
976     }
977     return GST_FLOW_WRONG_STATE;
978   }
979 pull_error:
980   {
981     GST_DEBUG ("Error getting %ldd bytes from the sinkpad!", desired);
982     return res;
983   }
984 push_error:
985   {
986     GST_DEBUG ("Error pushing on srcpad");
987     return res;
988   }
989 }
990
991 static void
992 gst_wavparse_loop (GstPad * pad)
993 {
994   GstFlowReturn ret;
995   GstWavParse *wav = GST_WAVPARSE (GST_PAD_PARENT (pad));
996
997   switch (wav->state) {
998     case GST_WAVPARSE_START:
999       if ((ret = gst_wavparse_stream_init (wav)) != GST_FLOW_OK)
1000         goto pause;
1001
1002       wav->state = GST_WAVPARSE_HEADER;
1003       /* fall-through */
1004
1005     case GST_WAVPARSE_HEADER:
1006       if ((ret = gst_wavparse_stream_headers (wav)) != GST_FLOW_OK)
1007         goto pause;
1008
1009       wav->state = GST_WAVPARSE_DATA;
1010       /* fall-through */
1011     case GST_WAVPARSE_DATA:
1012       if (wav->seek_event) {
1013         gst_pad_push_event (wav->srcpad, wav->seek_event);
1014         wav->seek_event = NULL;
1015       }
1016       if ((ret = gst_wavparse_stream_data (wav)) != GST_FLOW_OK)
1017         goto pause;
1018       break;
1019     default:
1020       g_assert_not_reached ();
1021   }
1022
1023   return;
1024
1025 pause:
1026   GST_LOG_OBJECT (wav, "pausing task %d", ret);
1027   gst_pad_pause_task (wav->sinkpad);
1028   if (GST_FLOW_IS_FATAL (ret)) {
1029     /* for fatal errors we post an error message */
1030     GST_ELEMENT_ERROR (wav, STREAM, STOPPED,
1031         ("streaming stopped, reason %s", gst_flow_get_name (ret)),
1032         ("streaming stopped, reason %s", gst_flow_get_name (ret)));
1033     gst_pad_push_event (wav->srcpad, gst_event_new_eos ());
1034   }
1035 }
1036
1037 #if 0
1038 /* convert and query stuff */
1039 static const GstFormat *
1040 gst_wavparse_get_formats (GstPad * pad)
1041 {
1042   static GstFormat formats[] = {
1043     GST_FORMAT_TIME,
1044     GST_FORMAT_BYTES,
1045     GST_FORMAT_DEFAULT,         /* a "frame", ie a set of samples per Hz */
1046     0
1047   };
1048
1049   return formats;
1050 }
1051 #endif
1052
1053 static gboolean
1054 gst_wavparse_pad_convert (GstPad * pad,
1055     GstFormat src_format, gint64 src_value,
1056     GstFormat * dest_format, gint64 * dest_value)
1057 {
1058   GstWavParse *wavparse;
1059   gboolean res = TRUE;
1060
1061   wavparse = GST_WAVPARSE (gst_pad_get_parent (pad));
1062
1063   if (wavparse->bytes_per_sample == 0)
1064     goto no_bytes_per_sample;
1065
1066   if (wavparse->bps == 0)
1067     goto no_bps;
1068
1069   switch (src_format) {
1070     case GST_FORMAT_BYTES:
1071       switch (*dest_format) {
1072         case GST_FORMAT_DEFAULT:
1073           *dest_value = src_value / wavparse->bytes_per_sample;
1074           break;
1075         case GST_FORMAT_TIME:
1076           *dest_value = src_value * GST_SECOND / wavparse->bps;
1077           break;
1078         default:
1079           res = FALSE;
1080           goto done;
1081       }
1082       *dest_value -= *dest_value % wavparse->bytes_per_sample;
1083       break;
1084
1085     case GST_FORMAT_DEFAULT:
1086       switch (*dest_format) {
1087         case GST_FORMAT_BYTES:
1088           *dest_value = src_value * wavparse->bytes_per_sample;
1089           break;
1090         case GST_FORMAT_TIME:
1091           *dest_value = src_value * GST_SECOND / wavparse->rate;
1092           break;
1093         default:
1094           res = FALSE;
1095           goto done;
1096       }
1097       break;
1098
1099     case GST_FORMAT_TIME:
1100       switch (*dest_format) {
1101         case GST_FORMAT_BYTES:
1102           /* make sure we end up on a sample boundary */
1103           *dest_value =
1104               (src_value * wavparse->rate / GST_SECOND) * wavparse->blockalign;
1105           break;
1106         case GST_FORMAT_DEFAULT:
1107           *dest_value = src_value * wavparse->rate / GST_SECOND;
1108           break;
1109         default:
1110           res = FALSE;
1111           goto done;
1112       }
1113       break;
1114
1115     default:
1116       res = FALSE;
1117       goto done;
1118   }
1119
1120 done:
1121   gst_object_unref (wavparse);
1122
1123   return res;
1124
1125   /* ERRORS */
1126 no_bytes_per_sample:
1127   {
1128     GST_DEBUG
1129         ("bytes_per_sample 0, probably an mp3 - channels %d, width %d",
1130         wavparse->channels, wavparse->width);
1131     res = FALSE;
1132     goto done;
1133   }
1134 no_bps:
1135   {
1136     g_warning ("bps is 0, internal error\n");
1137     res = FALSE;
1138     goto done;
1139   }
1140 }
1141
1142 static const GstQueryType *
1143 gst_wavparse_get_query_types (GstPad * pad)
1144 {
1145   static const GstQueryType types[] = {
1146     GST_QUERY_POSITION,
1147     0
1148   };
1149
1150   return types;
1151 }
1152
1153 /* handle queries for location and length in requested format */
1154 static gboolean
1155 gst_wavparse_pad_query (GstPad * pad, GstQuery * query)
1156 {
1157   gboolean res = TRUE;
1158   GstWavParse *wav = GST_WAVPARSE (GST_PAD_PARENT (pad));
1159
1160   /* only if we know */
1161   if (wav->state != GST_WAVPARSE_DATA)
1162     return FALSE;
1163
1164   switch (GST_QUERY_TYPE (query)) {
1165     case GST_QUERY_POSITION:
1166     {
1167       gint64 curb;
1168       gint64 cur;
1169       GstFormat format;
1170       gboolean res = TRUE;
1171
1172       curb = wav->offset - wav->datastart;
1173       gst_query_parse_position (query, &format, NULL);
1174
1175       switch (format) {
1176         case GST_FORMAT_TIME:
1177           res &=
1178               gst_wavparse_pad_convert (pad, GST_FORMAT_BYTES, curb,
1179               &format, &cur);
1180           break;
1181         default:
1182           format = GST_FORMAT_BYTES;
1183           cur = curb;
1184           break;
1185       }
1186       if (res)
1187         gst_query_set_position (query, format, cur);
1188       break;
1189     }
1190     case GST_QUERY_DURATION:
1191     {
1192       gint64 endb;
1193       gint64 end;
1194       GstFormat format;
1195       gboolean res = TRUE;
1196
1197       endb = wav->datasize;
1198       gst_query_parse_duration (query, &format, NULL);
1199
1200       switch (format) {
1201         case GST_FORMAT_TIME:
1202           res &=
1203               gst_wavparse_pad_convert (pad, GST_FORMAT_BYTES, endb,
1204               &format, &end);
1205           break;
1206         default:
1207           format = GST_FORMAT_BYTES;
1208           end = endb;
1209           break;
1210       }
1211       if (res)
1212         gst_query_set_duration (query, format, end);
1213       break;
1214     }
1215     case GST_QUERY_CONVERT:
1216     {
1217       gint64 srcvalue, dstvalue;
1218       GstFormat srcformat, dstformat;
1219
1220       gst_query_parse_convert (query, &srcformat, &srcvalue,
1221           &dstformat, &dstvalue);
1222       res &=
1223           gst_wavparse_pad_convert (pad, srcformat, srcvalue,
1224           &dstformat, &dstvalue);
1225       if (res)
1226         gst_query_set_convert (query, srcformat, srcvalue, dstformat, dstvalue);
1227       break;
1228     }
1229     default:
1230       res = FALSE;
1231       break;
1232   }
1233   return res;
1234 }
1235
1236 static gboolean
1237 gst_wavparse_srcpad_event (GstPad * pad, GstEvent * event)
1238 {
1239   GstWavParse *wavparse = GST_WAVPARSE (GST_PAD_PARENT (pad));
1240   gboolean res = TRUE;
1241
1242   GST_DEBUG ("event %d", GST_EVENT_TYPE (event));
1243
1244   switch (GST_EVENT_TYPE (event)) {
1245     case GST_EVENT_SEEK:
1246     {
1247       gdouble rate;
1248       GstFormat format;
1249       GstSeekFlags flags;
1250       GstSeekType start_type, stop_type;
1251       gint64 start, stop;
1252       GstFormat bformat = GST_FORMAT_BYTES;
1253       gint64 bstart, bstop;
1254       gboolean update_start = TRUE;
1255       gboolean update_stop = TRUE;
1256
1257       gst_event_parse_seek (event, &rate, &format, &flags,
1258           &start_type, &start, &stop_type, &stop);
1259
1260       GST_DEBUG ("seek format %d", format);
1261
1262       /* find the corresponding byte position */
1263       if (format != GST_FORMAT_BYTES) {
1264         res &= gst_wavparse_pad_convert (pad, format, start, &bformat, &bstart);
1265         res &= gst_wavparse_pad_convert (pad, format, stop, &bformat, &bstop);
1266         if (!res)
1267           goto done;
1268       }
1269
1270       switch (start_type) {
1271         case GST_SEEK_TYPE_CUR:
1272           bstart = wavparse->segment_start + bstart;
1273           break;
1274         case GST_SEEK_TYPE_END:
1275           bstart = wavparse->datasize + bstart;
1276           break;
1277         case GST_SEEK_TYPE_NONE:
1278           bstart = wavparse->segment_start;
1279           update_start = FALSE;
1280           break;
1281         case GST_SEEK_TYPE_SET:
1282           break;
1283       }
1284       bstart = CLAMP (bstart, 0, wavparse->datasize);
1285
1286       switch (stop_type) {
1287         case GST_SEEK_TYPE_CUR:
1288           bstop = wavparse->segment_stop + bstop;
1289           break;
1290         case GST_SEEK_TYPE_END:
1291           bstop = wavparse->datasize + bstop;
1292           break;
1293         case GST_SEEK_TYPE_NONE:
1294           bstop = wavparse->segment_stop;
1295           update_stop = FALSE;
1296           break;
1297         case GST_SEEK_TYPE_SET:
1298           break;
1299       }
1300       bstop = CLAMP (bstop, 0, wavparse->datasize);
1301
1302       /* now store the values */
1303       wavparse->segment_rate = rate;
1304       wavparse->segment_flags = flags;
1305       wavparse->segment_start = bstart;
1306       wavparse->segment_stop = bstop;
1307
1308       gst_wavparse_handle_seek (wavparse, update_stop || update_start);
1309       break;
1310     }
1311     default:
1312       res = FALSE;
1313       break;
1314   }
1315
1316 done:
1317   gst_event_unref (event);
1318
1319   return res;
1320 }
1321
1322 static gboolean
1323 gst_wavparse_sink_activate (GstPad * sinkpad)
1324 {
1325   if (gst_pad_check_pull_range (sinkpad))
1326     return gst_pad_activate_pull (sinkpad, TRUE);
1327
1328   return FALSE;
1329 };
1330
1331 static gboolean
1332 gst_wavparse_sink_activate_pull (GstPad * sinkpad, gboolean active)
1333 {
1334   if (active) {
1335     /* if we have a scheduler we can start the task */
1336     gst_pad_start_task (sinkpad, (GstTaskFunction) gst_wavparse_loop, sinkpad);
1337   } else {
1338     gst_pad_stop_task (sinkpad);
1339   }
1340
1341   return TRUE;
1342 };
1343
1344 static GstStateChangeReturn
1345 gst_wavparse_change_state (GstElement * element, GstStateChange transition)
1346 {
1347   GstStateChangeReturn ret;
1348   GstWavParse *wav = GST_WAVPARSE (element);
1349
1350   switch (transition) {
1351     case GST_STATE_CHANGE_NULL_TO_READY:
1352       break;
1353     case GST_STATE_CHANGE_READY_TO_PAUSED:
1354       wav->state = GST_WAVPARSE_START;
1355       break;
1356     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1357       break;
1358     default:
1359       break;
1360   }
1361
1362   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1363
1364   switch (transition) {
1365     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1366       break;
1367     case GST_STATE_CHANGE_PAUSED_TO_READY:
1368       gst_wavparse_destroy_sourcepad (wav);
1369       gst_wavparse_reset (wav);
1370       break;
1371     case GST_STATE_CHANGE_READY_TO_NULL:
1372       break;
1373     default:
1374       break;
1375   }
1376   return ret;
1377 }
1378
1379 static gboolean
1380 plugin_init (GstPlugin * plugin)
1381 {
1382   gst_riff_init ();
1383
1384   return gst_element_register (plugin, "wavparse", GST_RANK_PRIMARY,
1385       GST_TYPE_WAVPARSE);
1386 }
1387
1388 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1389     GST_VERSION_MINOR,
1390     "wavparse",
1391     "Parse a .wav file into raw audio",
1392     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN)