tizen 2.0 init
[framework/multimedia/gst-plugins-good0.10.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  * Copyright (C) <2006> Nokia Corporation, Stefan Kost <stefan.kost@nokia.com>.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 /**
23  * SECTION:element-wavparse
24  *
25  * Parse a .wav file into raw or compressed audio.
26  *
27  * Wavparse supports both push and pull mode operations, making it possible to
28  * stream from a network source.
29  *
30  * <refsect2>
31  * <title>Example launch line</title>
32  * |[
33  * gst-launch filesrc location=sine.wav ! wavparse ! audioconvert ! alsasink
34  * ]| Read a wav file and output to the soundcard using the ALSA element. The
35  * wav file is assumed to contain raw uncompressed samples.
36  * |[
37  * gst-launch gnomevfssrc location=http://www.example.org/sine.wav ! queue ! wavparse ! audioconvert ! alsasink
38  * ]| Stream data from a network url.
39  * </refsect2>
40  *
41  * Last reviewed on 2007-02-14 (0.10.6)
42  */
43
44 /*
45  * TODO:
46  * http://replaygain.hydrogenaudio.org/file_format_wav.html
47  */
48
49 #ifdef HAVE_CONFIG_H
50 #include "config.h"
51 #endif
52
53 /* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
54  * with newer GLib versions (>= 2.31.0) */
55 #define GLIB_DISABLE_DEPRECATION_WARNINGS
56
57 #include <string.h>
58 #include <math.h>
59
60 #include "gstwavparse.h"
61 #include "gst/riff/riff-ids.h"
62 #include "gst/riff/riff-media.h"
63 #include <gst/base/gsttypefindhelper.h>
64 #include <gst/gst-i18n-plugin.h>
65
66 GST_DEBUG_CATEGORY_STATIC (wavparse_debug);
67 #define GST_CAT_DEFAULT (wavparse_debug)
68
69 static void gst_wavparse_dispose (GObject * object);
70
71 static gboolean gst_wavparse_sink_activate (GstPad * sinkpad);
72 static gboolean gst_wavparse_sink_activate_pull (GstPad * sinkpad,
73     gboolean active);
74 static gboolean gst_wavparse_send_event (GstElement * element,
75     GstEvent * event);
76 static GstStateChangeReturn gst_wavparse_change_state (GstElement * element,
77     GstStateChange transition);
78
79 static const GstQueryType *gst_wavparse_get_query_types (GstPad * pad);
80 static gboolean gst_wavparse_pad_query (GstPad * pad, GstQuery * query);
81 static gboolean gst_wavparse_pad_convert (GstPad * pad,
82     GstFormat src_format,
83     gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
84
85 static GstFlowReturn gst_wavparse_chain (GstPad * pad, GstBuffer * buf);
86 static gboolean gst_wavparse_sink_event (GstPad * pad, GstEvent * event);
87 static void gst_wavparse_loop (GstPad * pad);
88 static gboolean gst_wavparse_srcpad_event (GstPad * pad, GstEvent * event);
89
90 static GstStaticPadTemplate sink_template_factory =
91 GST_STATIC_PAD_TEMPLATE ("wavparse_sink",
92     GST_PAD_SINK,
93     GST_PAD_ALWAYS,
94     GST_STATIC_CAPS ("audio/x-wav")
95     );
96
97 #define DEBUG_INIT(bla) \
98   GST_DEBUG_CATEGORY_INIT (wavparse_debug, "wavparse", 0, "WAV parser");
99
100 GST_BOILERPLATE_FULL (GstWavParse, gst_wavparse, GstElement,
101     GST_TYPE_ELEMENT, DEBUG_INIT);
102
103 static void
104 gst_wavparse_base_init (gpointer g_class)
105 {
106   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
107   GstPadTemplate *src_template;
108
109   /* register pads */
110   gst_element_class_add_static_pad_template (element_class,
111       &sink_template_factory);
112
113   src_template = gst_pad_template_new ("wavparse_src", GST_PAD_SRC,
114       GST_PAD_SOMETIMES, gst_riff_create_audio_template_caps ());
115   gst_element_class_add_pad_template (element_class, src_template);
116   gst_object_unref (src_template);
117
118   gst_element_class_set_details_simple (element_class, "WAV audio demuxer",
119       "Codec/Demuxer/Audio",
120       "Parse a .wav file into raw audio",
121       "Erik Walthinsen <omega@cse.ogi.edu>");
122 }
123
124 static void
125 gst_wavparse_class_init (GstWavParseClass * klass)
126 {
127   GstElementClass *gstelement_class;
128   GObjectClass *object_class;
129
130   gstelement_class = (GstElementClass *) klass;
131   object_class = (GObjectClass *) klass;
132
133   parent_class = g_type_class_peek_parent (klass);
134
135   object_class->dispose = gst_wavparse_dispose;
136
137   gstelement_class->change_state = gst_wavparse_change_state;
138   gstelement_class->send_event = gst_wavparse_send_event;
139 }
140
141 static void
142 gst_wavparse_reset (GstWavParse * wav)
143 {
144   wav->state = GST_WAVPARSE_START;
145
146   /* These will all be set correctly in the fmt chunk */
147   wav->depth = 0;
148   wav->rate = 0;
149   wav->width = 0;
150   wav->channels = 0;
151   wav->blockalign = 0;
152   wav->bps = 0;
153   wav->fact = 0;
154   wav->offset = 0;
155   wav->end_offset = 0;
156   wav->dataleft = 0;
157   wav->datasize = 0;
158   wav->datastart = 0;
159   wav->duration = 0;
160   wav->got_fmt = FALSE;
161   wav->first = TRUE;
162
163   if (wav->seek_event)
164     gst_event_unref (wav->seek_event);
165   wav->seek_event = NULL;
166   if (wav->adapter) {
167     gst_adapter_clear (wav->adapter);
168     g_object_unref (wav->adapter);
169     wav->adapter = NULL;
170   }
171   if (wav->tags)
172     gst_tag_list_free (wav->tags);
173   wav->tags = NULL;
174   if (wav->caps)
175     gst_caps_unref (wav->caps);
176   wav->caps = NULL;
177   if (wav->start_segment)
178     gst_event_unref (wav->start_segment);
179   wav->start_segment = NULL;
180   if (wav->close_segment)
181     gst_event_unref (wav->close_segment);
182   wav->close_segment = NULL;
183 }
184
185 static void
186 gst_wavparse_dispose (GObject * object)
187 {
188   GstWavParse *wav = GST_WAVPARSE (object);
189
190   GST_DEBUG_OBJECT (wav, "WAV: Dispose");
191   gst_wavparse_reset (wav);
192
193   G_OBJECT_CLASS (parent_class)->dispose (object);
194 }
195
196 static void
197 gst_wavparse_init (GstWavParse * wavparse, GstWavParseClass * g_class)
198 {
199   gst_wavparse_reset (wavparse);
200
201   /* sink */
202   wavparse->sinkpad =
203       gst_pad_new_from_static_template (&sink_template_factory, "sink");
204   gst_pad_set_activate_function (wavparse->sinkpad,
205       GST_DEBUG_FUNCPTR (gst_wavparse_sink_activate));
206   gst_pad_set_activatepull_function (wavparse->sinkpad,
207       GST_DEBUG_FUNCPTR (gst_wavparse_sink_activate_pull));
208   gst_pad_set_chain_function (wavparse->sinkpad,
209       GST_DEBUG_FUNCPTR (gst_wavparse_chain));
210   gst_pad_set_event_function (wavparse->sinkpad,
211       GST_DEBUG_FUNCPTR (gst_wavparse_sink_event));
212   gst_element_add_pad (GST_ELEMENT_CAST (wavparse), wavparse->sinkpad);
213
214   /* src, will be created later */
215   wavparse->srcpad = NULL;
216 }
217
218 static void
219 gst_wavparse_destroy_sourcepad (GstWavParse * wavparse)
220 {
221   if (wavparse->srcpad) {
222     gst_element_remove_pad (GST_ELEMENT_CAST (wavparse), wavparse->srcpad);
223     wavparse->srcpad = NULL;
224   }
225 }
226
227 static void
228 gst_wavparse_create_sourcepad (GstWavParse * wavparse)
229 {
230   GstElementClass *klass = GST_ELEMENT_GET_CLASS (wavparse);
231   GstPadTemplate *src_template;
232
233   /* destroy previous one */
234   gst_wavparse_destroy_sourcepad (wavparse);
235
236   /* source */
237   src_template = gst_element_class_get_pad_template (klass, "wavparse_src");
238   wavparse->srcpad = gst_pad_new_from_template (src_template, "src");
239   gst_pad_use_fixed_caps (wavparse->srcpad);
240   gst_pad_set_query_type_function (wavparse->srcpad,
241       GST_DEBUG_FUNCPTR (gst_wavparse_get_query_types));
242   gst_pad_set_query_function (wavparse->srcpad,
243       GST_DEBUG_FUNCPTR (gst_wavparse_pad_query));
244   gst_pad_set_event_function (wavparse->srcpad,
245       GST_DEBUG_FUNCPTR (gst_wavparse_srcpad_event));
246
247   GST_DEBUG_OBJECT (wavparse, "srcpad created");
248 }
249
250 /* Compute (value * nom) % denom, avoiding overflow.  This can be used
251  * to perform ceiling or rounding division together with
252  * gst_util_uint64_scale[_int]. */
253 #define uint64_scale_modulo(val, nom, denom) \
254   ((val % denom) * (nom % denom) % denom)
255
256 /* Like gst_util_uint64_scale, but performs ceiling division. */
257 static guint64
258 uint64_ceiling_scale_int (guint64 val, gint num, gint denom)
259 {
260   guint64 result = gst_util_uint64_scale_int (val, num, denom);
261
262   if (uint64_scale_modulo (val, num, denom) == 0)
263     return result;
264   else
265     return result + 1;
266 }
267
268 /* Like gst_util_uint64_scale, but performs ceiling division. */
269 static guint64
270 uint64_ceiling_scale (guint64 val, guint64 num, guint64 denom)
271 {
272   guint64 result = gst_util_uint64_scale (val, num, denom);
273
274   if (uint64_scale_modulo (val, num, denom) == 0)
275     return result;
276   else
277     return result + 1;
278 }
279
280
281 /* FIXME: why is that not in use? */
282 #if 0
283 static void
284 gst_wavparse_parse_adtl (GstWavParse * wavparse, int len)
285 {
286   guint32 got_bytes;
287   GstByteStream *bs = wavparse->bs;
288   gst_riff_chunk *temp_chunk, chunk;
289   guint8 *tempdata;
290   struct _gst_riff_labl labl, *temp_labl;
291   struct _gst_riff_ltxt ltxt, *temp_ltxt;
292   struct _gst_riff_note note, *temp_note;
293   char *label_name;
294   GstProps *props;
295   GstPropsEntry *entry;
296   GstCaps *new_caps;
297   GList *caps = NULL;
298
299   props = wavparse->metadata->properties;
300
301   while (len > 0) {
302     got_bytes =
303         gst_bytestream_peek_bytes (bs, &tempdata, sizeof (gst_riff_chunk));
304     if (got_bytes != sizeof (gst_riff_chunk)) {
305       return;
306     }
307     temp_chunk = (gst_riff_chunk *) tempdata;
308
309     chunk.id = GUINT32_FROM_LE (temp_chunk->id);
310     chunk.size = GUINT32_FROM_LE (temp_chunk->size);
311
312     if (chunk.size == 0) {
313       gst_bytestream_flush (bs, sizeof (gst_riff_chunk));
314       len -= sizeof (gst_riff_chunk);
315       continue;
316     }
317
318     switch (chunk.id) {
319       case GST_RIFF_adtl_labl:
320         got_bytes =
321             gst_bytestream_peek_bytes (bs, &tempdata,
322             sizeof (struct _gst_riff_labl));
323         if (got_bytes != sizeof (struct _gst_riff_labl)) {
324           return;
325         }
326
327         temp_labl = (struct _gst_riff_labl *) tempdata;
328         labl.id = GUINT32_FROM_LE (temp_labl->id);
329         labl.size = GUINT32_FROM_LE (temp_labl->size);
330         labl.identifier = GUINT32_FROM_LE (temp_labl->identifier);
331
332         gst_bytestream_flush (bs, sizeof (struct _gst_riff_labl));
333         len -= sizeof (struct _gst_riff_labl);
334
335         got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, labl.size - 4);
336         if (got_bytes != labl.size - 4) {
337           return;
338         }
339
340         label_name = (char *) tempdata;
341
342         gst_bytestream_flush (bs, ((labl.size - 4) + 1) & ~1);
343         len -= (((labl.size - 4) + 1) & ~1);
344
345         new_caps = gst_caps_new ("label",
346             "application/x-gst-metadata",
347             gst_props_new ("identifier", G_TYPE_INT (labl.identifier),
348                 "name", G_TYPE_STRING (label_name), NULL));
349
350         if (gst_props_get (props, "labels", &caps, NULL)) {
351           caps = g_list_append (caps, new_caps);
352         } else {
353           caps = g_list_append (NULL, new_caps);
354
355           entry = gst_props_entry_new ("labels", GST_PROPS_GLIST (caps));
356           gst_props_add_entry (props, entry);
357         }
358
359         break;
360
361       case GST_RIFF_adtl_ltxt:
362         got_bytes =
363             gst_bytestream_peek_bytes (bs, &tempdata,
364             sizeof (struct _gst_riff_ltxt));
365         if (got_bytes != sizeof (struct _gst_riff_ltxt)) {
366           return;
367         }
368
369         temp_ltxt = (struct _gst_riff_ltxt *) tempdata;
370         ltxt.id = GUINT32_FROM_LE (temp_ltxt->id);
371         ltxt.size = GUINT32_FROM_LE (temp_ltxt->size);
372         ltxt.identifier = GUINT32_FROM_LE (temp_ltxt->identifier);
373         ltxt.length = GUINT32_FROM_LE (temp_ltxt->length);
374         ltxt.purpose = GUINT32_FROM_LE (temp_ltxt->purpose);
375         ltxt.country = GUINT16_FROM_LE (temp_ltxt->country);
376         ltxt.language = GUINT16_FROM_LE (temp_ltxt->language);
377         ltxt.dialect = GUINT16_FROM_LE (temp_ltxt->dialect);
378         ltxt.codepage = GUINT16_FROM_LE (temp_ltxt->codepage);
379
380         gst_bytestream_flush (bs, sizeof (struct _gst_riff_ltxt));
381         len -= sizeof (struct _gst_riff_ltxt);
382
383         if (ltxt.size - 20 > 0) {
384           got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, ltxt.size - 20);
385           if (got_bytes != ltxt.size - 20) {
386             return;
387           }
388
389           gst_bytestream_flush (bs, ((ltxt.size - 20) + 1) & ~1);
390           len -= (((ltxt.size - 20) + 1) & ~1);
391
392           label_name = (char *) tempdata;
393         } else {
394           label_name = "";
395         }
396
397         new_caps = gst_caps_new ("ltxt",
398             "application/x-gst-metadata",
399             gst_props_new ("identifier", G_TYPE_INT (ltxt.identifier),
400                 "name", G_TYPE_STRING (label_name),
401                 "length", G_TYPE_INT (ltxt.length), NULL));
402
403         if (gst_props_get (props, "ltxts", &caps, NULL)) {
404           caps = g_list_append (caps, new_caps);
405         } else {
406           caps = g_list_append (NULL, new_caps);
407
408           entry = gst_props_entry_new ("ltxts", GST_PROPS_GLIST (caps));
409           gst_props_add_entry (props, entry);
410         }
411
412         break;
413
414       case GST_RIFF_adtl_note:
415         got_bytes =
416             gst_bytestream_peek_bytes (bs, &tempdata,
417             sizeof (struct _gst_riff_note));
418         if (got_bytes != sizeof (struct _gst_riff_note)) {
419           return;
420         }
421
422         temp_note = (struct _gst_riff_note *) tempdata;
423         note.id = GUINT32_FROM_LE (temp_note->id);
424         note.size = GUINT32_FROM_LE (temp_note->size);
425         note.identifier = GUINT32_FROM_LE (temp_note->identifier);
426
427         gst_bytestream_flush (bs, sizeof (struct _gst_riff_note));
428         len -= sizeof (struct _gst_riff_note);
429
430         got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, note.size - 4);
431         if (got_bytes != note.size - 4) {
432           return;
433         }
434
435         gst_bytestream_flush (bs, ((note.size - 4) + 1) & ~1);
436         len -= (((note.size - 4) + 1) & ~1);
437
438         label_name = (char *) tempdata;
439
440         new_caps = gst_caps_new ("note",
441             "application/x-gst-metadata",
442             gst_props_new ("identifier", G_TYPE_INT (note.identifier),
443                 "name", G_TYPE_STRING (label_name), NULL));
444
445         if (gst_props_get (props, "notes", &caps, NULL)) {
446           caps = g_list_append (caps, new_caps);
447         } else {
448           caps = g_list_append (NULL, new_caps);
449
450           entry = gst_props_entry_new ("notes", GST_PROPS_GLIST (caps));
451           gst_props_add_entry (props, entry);
452         }
453
454         break;
455
456       default:
457         g_print ("Unknown chunk: %" GST_FOURCC_FORMAT "\n",
458             GST_FOURCC_ARGS (chunk.id));
459         return;
460     }
461   }
462
463   g_object_notify (G_OBJECT (wavparse), "metadata");
464 }
465
466 static void
467 gst_wavparse_parse_cues (GstWavParse * wavparse, int len)
468 {
469   guint32 got_bytes;
470   GstByteStream *bs = wavparse->bs;
471   struct _gst_riff_cue *temp_cue, cue;
472   struct _gst_riff_cuepoints *points;
473   guint8 *tempdata;
474   int i;
475   GList *cues = NULL;
476   GstPropsEntry *entry;
477
478   while (len > 0) {
479     int required;
480
481     got_bytes =
482         gst_bytestream_peek_bytes (bs, &tempdata,
483         sizeof (struct _gst_riff_cue));
484     temp_cue = (struct _gst_riff_cue *) tempdata;
485
486     /* fixup for our big endian friends */
487     cue.id = GUINT32_FROM_LE (temp_cue->id);
488     cue.size = GUINT32_FROM_LE (temp_cue->size);
489     cue.cuepoints = GUINT32_FROM_LE (temp_cue->cuepoints);
490
491     gst_bytestream_flush (bs, sizeof (struct _gst_riff_cue));
492     if (got_bytes != sizeof (struct _gst_riff_cue)) {
493       return;
494     }
495
496     len -= sizeof (struct _gst_riff_cue);
497
498     /* -4 because cue.size contains the cuepoints size
499        and we've already flushed that out of the system */
500     required = cue.size - 4;
501     got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, required);
502     gst_bytestream_flush (bs, ((required) + 1) & ~1);
503     if (got_bytes != required) {
504       return;
505     }
506
507     len -= (((cue.size - 4) + 1) & ~1);
508
509     /* now we have an array of struct _gst_riff_cuepoints in tempdata */
510     points = (struct _gst_riff_cuepoints *) tempdata;
511
512     for (i = 0; i < cue.cuepoints; i++) {
513       GstCaps *caps;
514
515       caps = gst_caps_new ("cues",
516           "application/x-gst-metadata",
517           gst_props_new ("identifier", G_TYPE_INT (points[i].identifier),
518               "position", G_TYPE_INT (points[i].offset), NULL));
519       cues = g_list_append (cues, caps);
520     }
521
522     entry = gst_props_entry_new ("cues", GST_PROPS_GLIST (cues));
523     gst_props_add_entry (wavparse->metadata->properties, entry);
524   }
525
526   g_object_notify (G_OBJECT (wavparse), "metadata");
527 }
528
529 /* Read 'fmt ' header */
530 static gboolean
531 gst_wavparse_fmt (GstWavParse * wav)
532 {
533   gst_riff_strf_auds *header = NULL;
534   GstCaps *caps;
535
536   if (!gst_riff_read_strf_auds (wav, &header))
537     goto no_fmt;
538
539   wav->format = header->format;
540   wav->rate = header->rate;
541   wav->channels = header->channels;
542   if (wav->channels == 0)
543     goto no_channels;
544
545   wav->blockalign = header->blockalign;
546   wav->width = (header->blockalign * 8) / header->channels;
547   wav->depth = header->size;
548   wav->bps = header->av_bps;
549   if (wav->bps <= 0)
550     goto no_bps;
551
552   /* Note: gst_riff_create_audio_caps might need to fix values in
553    * the header header depending on the format, so call it first */
554   caps = gst_riff_create_audio_caps (header->format, NULL, header, NULL);
555   g_free (header);
556
557   if (caps == NULL)
558     goto no_caps;
559
560   gst_wavparse_create_sourcepad (wav);
561   gst_pad_use_fixed_caps (wav->srcpad);
562   gst_pad_set_active (wav->srcpad, TRUE);
563   gst_pad_set_caps (wav->srcpad, caps);
564   gst_caps_free (caps);
565   gst_element_add_pad (GST_ELEMENT_CAST (wav), wav->srcpad);
566   gst_element_no_more_pads (GST_ELEMENT_CAST (wav));
567
568   GST_DEBUG ("frequency %d, channels %d", wav->rate, wav->channels);
569
570   return TRUE;
571
572   /* ERRORS */
573 no_fmt:
574   {
575     GST_ELEMENT_ERROR (wav, STREAM, TYPE_NOT_FOUND, (NULL),
576         ("No FMT tag found"));
577     return FALSE;
578   }
579 no_channels:
580   {
581     GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL),
582         ("Stream claims to contain zero channels - invalid data"));
583     g_free (header);
584     return FALSE;
585   }
586 no_bps:
587   {
588     GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL),
589         ("Stream claims to bitrate of <= zero - invalid data"));
590     g_free (header);
591     return FALSE;
592   }
593 no_caps:
594   {
595     GST_ELEMENT_ERROR (wav, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
596     return FALSE;
597   }
598 }
599
600 static gboolean
601 gst_wavparse_other (GstWavParse * wav)
602 {
603   guint32 tag, length;
604
605   if (!gst_riff_peek_head (wav, &tag, &length, NULL)) {
606     GST_WARNING_OBJECT (wav, "could not peek head");
607     return FALSE;
608   }
609   GST_DEBUG_OBJECT (wav, "got tag (%08x) %4.4s, length %d", tag,
610       (gchar *) & tag, length);
611
612   switch (tag) {
613     case GST_RIFF_TAG_LIST:
614       if (!(tag = gst_riff_peek_list (wav))) {
615         GST_WARNING_OBJECT (wav, "could not peek list");
616         return FALSE;
617       }
618
619       switch (tag) {
620         case GST_RIFF_LIST_INFO:
621           if (!gst_riff_read_list (wav, &tag) || !gst_riff_read_info (wav)) {
622             GST_WARNING_OBJECT (wav, "could not read list");
623             return FALSE;
624           }
625           break;
626
627         case GST_RIFF_LIST_adtl:
628           if (!gst_riff_read_skip (wav)) {
629             GST_WARNING_OBJECT (wav, "could not read skip");
630             return FALSE;
631           }
632           break;
633
634         default:
635           GST_DEBUG_OBJECT (wav, "skipping tag (%08x) %4.4s", tag,
636               (gchar *) & tag);
637           if (!gst_riff_read_skip (wav)) {
638             GST_WARNING_OBJECT (wav, "could not read skip");
639             return FALSE;
640           }
641           break;
642       }
643
644       break;
645
646     case GST_RIFF_TAG_data:
647       if (!gst_bytestream_flush (wav->bs, 8)) {
648         GST_WARNING_OBJECT (wav, "could not flush 8 bytes");
649         return FALSE;
650       }
651
652       GST_DEBUG_OBJECT (wav, "switching to data mode");
653       wav->state = GST_WAVPARSE_DATA;
654       wav->datastart = gst_bytestream_tell (wav->bs);
655       if (length == 0) {
656         guint64 file_length;
657
658         /* length is 0, data probably stretches to the end
659          * of file */
660         GST_DEBUG_OBJECT (wav, "length is 0 trying to find length");
661         /* get length of file */
662         file_length = gst_bytestream_length (wav->bs);
663         if (file_length == -1) {
664           GST_DEBUG_OBJECT (wav,
665               "could not get file length, assuming data to eof");
666           /* could not get length, assuming till eof */
667           length = G_MAXUINT32;
668         }
669         if (file_length > G_MAXUINT32) {
670           GST_DEBUG_OBJECT (wav, "file length %" G_GUINT64_FORMAT
671               ", clipping to 32 bits", file_length);
672           /* could not get length, assuming till eof */
673           length = G_MAXUINT32;
674         } else {
675           GST_DEBUG_OBJECT (wav, "file length %" G_GUINT64_FORMAT
676               ", datalength %u", file_length, length);
677           /* substract offset of datastart from length */
678           length = file_length - wav->datastart;
679           GST_DEBUG_OBJECT (wav, "datalength %u", length);
680         }
681       }
682       wav->datasize = (guint64) length;
683       GST_DEBUG_OBJECT (wav, "datasize = %ld", 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
705 static gboolean
706 gst_wavparse_parse_file_header (GstElement * element, GstBuffer * buf)
707 {
708   guint32 doctype;
709
710   if (!gst_riff_parse_file_header (element, buf, &doctype))
711     return FALSE;
712
713   if (doctype != GST_RIFF_RIFF_WAVE)
714     goto not_wav;
715
716   return TRUE;
717
718   /* ERRORS */
719 not_wav:
720   {
721     GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL),
722         ("File is not a WAVE file: %" GST_FOURCC_FORMAT,
723             GST_FOURCC_ARGS (doctype)));
724     return FALSE;
725   }
726 }
727
728 static GstFlowReturn
729 gst_wavparse_stream_init (GstWavParse * wav)
730 {
731   GstFlowReturn res;
732   GstBuffer *buf = NULL;
733
734   if ((res = gst_pad_pull_range (wav->sinkpad,
735               wav->offset, 12, &buf)) != GST_FLOW_OK)
736     return res;
737   else if (!gst_wavparse_parse_file_header (GST_ELEMENT_CAST (wav), buf))
738     return GST_FLOW_ERROR;
739
740   wav->offset += 12;
741
742   return GST_FLOW_OK;
743 }
744
745 static gboolean
746 gst_wavparse_time_to_bytepos (GstWavParse * wav, gint64 ts, gint64 * bytepos)
747 {
748   /* -1 always maps to -1 */
749   if (ts == -1) {
750     *bytepos = -1;
751     return TRUE;
752   }
753
754   /* 0 always maps to 0 */
755   if (ts == 0) {
756     *bytepos = 0;
757     return TRUE;
758   }
759
760   if (wav->bps > 0) {
761     *bytepos = uint64_ceiling_scale (ts, (guint64) wav->bps, GST_SECOND);
762     return TRUE;
763   } else if (wav->fact) {
764     guint64 bps =
765         gst_util_uint64_scale_int (wav->datasize, wav->rate, wav->fact);
766     *bytepos = uint64_ceiling_scale (ts, bps, GST_SECOND);
767     return TRUE;
768   }
769
770   return FALSE;
771 }
772
773 /* This function is used to perform seeks on the element.
774  *
775  * It also works when event is NULL, in which case it will just
776  * start from the last configured segment. This technique is
777  * used when activating the element and to perform the seek in
778  * READY.
779  */
780 static gboolean
781 gst_wavparse_perform_seek (GstWavParse * wav, GstEvent * event)
782 {
783   gboolean res;
784   gdouble rate;
785   GstFormat format, bformat;
786   GstSeekFlags flags;
787   GstSeekType cur_type = GST_SEEK_TYPE_NONE, stop_type;
788   gint64 cur, stop, upstream_size;
789   gboolean flush;
790   gboolean update;
791   GstSegment seeksegment = { 0, };
792   gint64 last_stop;
793
794   if (event) {
795     GST_DEBUG_OBJECT (wav, "doing seek with event");
796
797     gst_event_parse_seek (event, &rate, &format, &flags,
798         &cur_type, &cur, &stop_type, &stop);
799
800     /* no negative rates yet */
801     if (rate < 0.0)
802       goto negative_rate;
803
804     if (format != wav->segment.format) {
805       GST_INFO_OBJECT (wav, "converting seek-event from %s to %s",
806           gst_format_get_name (format),
807           gst_format_get_name (wav->segment.format));
808       res = TRUE;
809       if (cur_type != GST_SEEK_TYPE_NONE)
810         res =
811             gst_pad_query_convert (wav->srcpad, format, cur,
812             &wav->segment.format, &cur);
813       if (res && stop_type != GST_SEEK_TYPE_NONE)
814         res =
815             gst_pad_query_convert (wav->srcpad, format, stop,
816             &wav->segment.format, &stop);
817       if (!res)
818         goto no_format;
819
820       format = wav->segment.format;
821     }
822   } else {
823     GST_DEBUG_OBJECT (wav, "doing seek without event");
824     flags = 0;
825     rate = 1.0;
826     cur_type = GST_SEEK_TYPE_SET;
827     stop_type = GST_SEEK_TYPE_SET;
828   }
829
830   /* in push mode, we must delegate to upstream */
831   if (wav->streaming) {
832     gboolean res = FALSE;
833
834     /* if streaming not yet started; only prepare initial newsegment */
835     if (!event || wav->state != GST_WAVPARSE_DATA) {
836       if (wav->start_segment)
837         gst_event_unref (wav->start_segment);
838       wav->start_segment =
839           gst_event_new_new_segment (FALSE, wav->segment.rate,
840           wav->segment.format, wav->segment.last_stop, wav->segment.duration,
841           wav->segment.last_stop);
842       res = TRUE;
843     } else {
844       /* convert seek positions to byte positions in data sections */
845       if (format == GST_FORMAT_TIME) {
846         /* should not fail */
847         if (!gst_wavparse_time_to_bytepos (wav, cur, &cur))
848           goto no_position;
849         if (!gst_wavparse_time_to_bytepos (wav, stop, &stop))
850           goto no_position;
851       }
852       /* mind sample boundary and header */
853       if (cur >= 0) {
854         cur -= (cur % wav->bytes_per_sample);
855         cur += wav->datastart;
856       }
857       if (stop >= 0) {
858         stop -= (stop % wav->bytes_per_sample);
859         stop += wav->datastart;
860       }
861       GST_DEBUG_OBJECT (wav, "Pushing BYTE seek rate %g, "
862           "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur,
863           stop);
864       /* BYTE seek event */
865       event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, cur,
866           stop_type, stop);
867       res = gst_pad_push_event (wav->sinkpad, event);
868     }
869     return res;
870   }
871
872   /* get flush flag */
873   flush = flags & GST_SEEK_FLAG_FLUSH;
874
875   /* now we need to make sure the streaming thread is stopped. We do this by
876    * either sending a FLUSH_START event downstream which will cause the
877    * streaming thread to stop with a WRONG_STATE.
878    * For a non-flushing seek we simply pause the task, which will happen as soon
879    * as it completes one iteration (and thus might block when the sink is
880    * blocking in preroll). */
881   if (flush) {
882     if (wav->srcpad) {
883       GST_DEBUG_OBJECT (wav, "sending flush start");
884       gst_pad_push_event (wav->srcpad, gst_event_new_flush_start ());
885     }
886   } else {
887     gst_pad_pause_task (wav->sinkpad);
888   }
889
890   /* we should now be able to grab the streaming thread because we stopped it
891    * with the above flush/pause code */
892   GST_PAD_STREAM_LOCK (wav->sinkpad);
893
894   /* save current position */
895   last_stop = wav->segment.last_stop;
896
897   GST_DEBUG_OBJECT (wav, "stopped streaming at %" G_GINT64_FORMAT, last_stop);
898
899   /* copy segment, we need this because we still need the old
900    * segment when we close the current segment. */
901   memcpy (&seeksegment, &wav->segment, sizeof (GstSegment));
902
903   /* configure the seek parameters in the seeksegment. We will then have the
904    * right values in the segment to perform the seek */
905   if (event) {
906     GST_DEBUG_OBJECT (wav, "configuring seek");
907     gst_segment_set_seek (&seeksegment, rate, format, flags,
908         cur_type, cur, stop_type, stop, &update);
909   }
910
911   /* figure out the last position we need to play. If it's configured (stop !=
912    * -1), use that, else we play until the total duration of the file */
913   if ((stop = seeksegment.stop) == -1)
914     stop = seeksegment.duration;
915
916   GST_DEBUG_OBJECT (wav, "cur_type =%d", cur_type);
917   if ((cur_type != GST_SEEK_TYPE_NONE)) {
918     /* bring offset to bytes, if the bps is 0, we have the segment in BYTES and
919      * we can just copy the last_stop. If not, we use the bps to convert TIME to
920      * bytes. */
921     if (!gst_wavparse_time_to_bytepos (wav, seeksegment.last_stop,
922             (gint64 *) & wav->offset))
923       wav->offset = seeksegment.last_stop;
924     GST_LOG_OBJECT (wav, "offset=%" G_GUINT64_FORMAT, wav->offset);
925     wav->offset -= (wav->offset % wav->bytes_per_sample);
926     GST_LOG_OBJECT (wav, "offset=%" G_GUINT64_FORMAT, wav->offset);
927     wav->offset += wav->datastart;
928     GST_LOG_OBJECT (wav, "offset=%" G_GUINT64_FORMAT, wav->offset);
929   } else {
930     GST_LOG_OBJECT (wav, "continue from offset=%" G_GUINT64_FORMAT,
931         wav->offset);
932   }
933
934   if (stop_type != GST_SEEK_TYPE_NONE) {
935     if (!gst_wavparse_time_to_bytepos (wav, stop, (gint64 *) & wav->end_offset))
936       wav->end_offset = stop;
937     GST_LOG_OBJECT (wav, "end_offset=%" G_GUINT64_FORMAT, wav->end_offset);
938     wav->end_offset -= (wav->end_offset % wav->bytes_per_sample);
939     GST_LOG_OBJECT (wav, "end_offset=%" G_GUINT64_FORMAT, wav->end_offset);
940     wav->end_offset += wav->datastart;
941     GST_LOG_OBJECT (wav, "end_offset=%" G_GUINT64_FORMAT, wav->end_offset);
942   } else {
943     GST_LOG_OBJECT (wav, "continue to end_offset=%" G_GUINT64_FORMAT,
944         wav->end_offset);
945   }
946
947   /* make sure filesize is not exceeded due to rounding errors or so,
948    * same precaution as in _stream_headers */
949   bformat = GST_FORMAT_BYTES;
950   if (gst_pad_query_peer_duration (wav->sinkpad, &bformat, &upstream_size))
951     wav->end_offset = MIN (wav->end_offset, upstream_size);
952
953   /* this is the range of bytes we will use for playback */
954   wav->offset = MIN (wav->offset, wav->end_offset);
955   wav->dataleft = wav->end_offset - wav->offset;
956
957   GST_DEBUG_OBJECT (wav,
958       "seek: rate %lf, offset %" G_GUINT64_FORMAT ", end %" G_GUINT64_FORMAT
959       ", segment %" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT, rate, wav->offset,
960       wav->end_offset, GST_TIME_ARGS (seeksegment.start), GST_TIME_ARGS (stop));
961
962   /* prepare for streaming again */
963   if (wav->srcpad) {
964     if (flush) {
965       /* if we sent a FLUSH_START, we now send a FLUSH_STOP */
966       GST_DEBUG_OBJECT (wav, "sending flush stop");
967       gst_pad_push_event (wav->srcpad, gst_event_new_flush_stop ());
968     } else if (wav->segment_running) {
969       /* we are running the current segment and doing a non-flushing seek,
970        * close the segment first based on the previous last_stop. */
971       GST_DEBUG_OBJECT (wav, "closing running segment %" G_GINT64_FORMAT
972           " to %" G_GINT64_FORMAT, wav->segment.start, wav->segment.last_stop);
973
974       /* queue the segment for sending in the stream thread */
975       if (wav->close_segment)
976         gst_event_unref (wav->close_segment);
977       wav->close_segment = gst_event_new_new_segment (TRUE,
978           wav->segment.rate, wav->segment.format,
979           wav->segment.start, wav->segment.last_stop, wav->segment.start);
980     }
981   }
982
983   /* now we did the seek and can activate the new segment values */
984   memcpy (&wav->segment, &seeksegment, sizeof (GstSegment));
985
986   /* if we're doing a segment seek, post a SEGMENT_START message */
987   if (wav->segment.flags & GST_SEEK_FLAG_SEGMENT) {
988     gst_element_post_message (GST_ELEMENT_CAST (wav),
989         gst_message_new_segment_start (GST_OBJECT_CAST (wav),
990             wav->segment.format, wav->segment.last_stop));
991   }
992
993   /* now create the newsegment */
994   GST_DEBUG_OBJECT (wav, "Creating newsegment from %" G_GINT64_FORMAT
995       " to %" G_GINT64_FORMAT, wav->segment.last_stop, stop);
996
997   /* store the newsegment event so it can be sent from the streaming thread. */
998   if (wav->start_segment)
999     gst_event_unref (wav->start_segment);
1000   wav->start_segment =
1001       gst_event_new_new_segment (FALSE, wav->segment.rate,
1002       wav->segment.format, wav->segment.last_stop, stop,
1003       wav->segment.last_stop);
1004
1005   /* mark discont if we are going to stream from another position. */
1006   if (last_stop != wav->segment.last_stop) {
1007     GST_DEBUG_OBJECT (wav, "mark DISCONT, we did a seek to another position");
1008     wav->discont = TRUE;
1009   }
1010
1011   /* and start the streaming task again */
1012   wav->segment_running = TRUE;
1013   if (!wav->streaming) {
1014     gst_pad_start_task (wav->sinkpad, (GstTaskFunction) gst_wavparse_loop,
1015         wav->sinkpad);
1016   }
1017
1018   GST_PAD_STREAM_UNLOCK (wav->sinkpad);
1019
1020   return TRUE;
1021
1022   /* ERRORS */
1023 negative_rate:
1024   {
1025     GST_DEBUG_OBJECT (wav, "negative playback rates are not supported yet.");
1026     return FALSE;
1027   }
1028 no_format:
1029   {
1030     GST_DEBUG_OBJECT (wav, "unsupported format given, seek aborted.");
1031     return FALSE;
1032   }
1033 no_position:
1034   {
1035     GST_DEBUG_OBJECT (wav,
1036         "Could not determine byte position for desired time");
1037     return FALSE;
1038   }
1039 }
1040
1041 /*
1042  * gst_wavparse_peek_chunk_info:
1043  * @wav Wavparse object
1044  * @tag holder for tag
1045  * @size holder for tag size
1046  *
1047  * Peek next chunk info (tag and size)
1048  *
1049  * Returns: %TRUE when the chunk info (header) is available
1050  */
1051 static gboolean
1052 gst_wavparse_peek_chunk_info (GstWavParse * wav, guint32 * tag, guint32 * size)
1053 {
1054   const guint8 *data = NULL;
1055
1056   if (gst_adapter_available (wav->adapter) < 8)
1057     return FALSE;
1058
1059   data = gst_adapter_peek (wav->adapter, 8);
1060   *tag = GST_READ_UINT32_LE (data);
1061   *size = GST_READ_UINT32_LE (data + 4);
1062
1063   GST_DEBUG ("Next chunk size is %d bytes, type %" GST_FOURCC_FORMAT, *size,
1064       GST_FOURCC_ARGS (*tag));
1065
1066   return TRUE;
1067 }
1068
1069 /*
1070  * gst_wavparse_peek_chunk:
1071  * @wav Wavparse object
1072  * @tag holder for tag
1073  * @size holder for tag size
1074  *
1075  * Peek enough data for one full chunk
1076  *
1077  * Returns: %TRUE when the full chunk is available
1078  */
1079 static gboolean
1080 gst_wavparse_peek_chunk (GstWavParse * wav, guint32 * tag, guint32 * size)
1081 {
1082   guint32 peek_size = 0;
1083   guint available;
1084
1085   if (!gst_wavparse_peek_chunk_info (wav, tag, size))
1086     return FALSE;
1087
1088   /* size 0 -> empty data buffer would surprise most callers,
1089    * large size -> do not bother trying to squeeze that into adapter,
1090    * so we throw poor man's exception, which can be caught if caller really
1091    * wants to handle 0 size chunk */
1092   if (!(*size) || (*size) >= (1 << 30)) {
1093     GST_INFO ("Invalid/unexpected chunk size %d for tag %" GST_FOURCC_FORMAT,
1094         *size, GST_FOURCC_ARGS (*tag));
1095     /* chain should give up */
1096     wav->abort_buffering = TRUE;
1097     return FALSE;
1098   }
1099   peek_size = (*size + 1) & ~1;
1100   available = gst_adapter_available (wav->adapter);
1101
1102   if (available >= (8 + peek_size)) {
1103     return TRUE;
1104   } else {
1105     GST_LOG ("but only %u bytes available now", available);
1106     return FALSE;
1107   }
1108 }
1109
1110 /*
1111  * gst_wavparse_calculate_duration:
1112  * @wav: wavparse object
1113  *
1114  * Calculate duration on demand and store in @wav. Prefer bps, but use fact as a
1115  * fallback.
1116  *
1117  * Returns: %TRUE if duration is available.
1118  */
1119 static gboolean
1120 gst_wavparse_calculate_duration (GstWavParse * wav)
1121 {
1122   if (wav->duration > 0)
1123     return TRUE;
1124
1125   if (wav->bps > 0) {
1126     GST_INFO_OBJECT (wav, "Got datasize %" G_GUINT64_FORMAT, wav->datasize);
1127     wav->duration =
1128         uint64_ceiling_scale (wav->datasize, GST_SECOND, (guint64) wav->bps);
1129     GST_INFO_OBJECT (wav, "Got duration (bps) %" GST_TIME_FORMAT,
1130         GST_TIME_ARGS (wav->duration));
1131     return TRUE;
1132   } else if (wav->fact) {
1133     wav->duration = uint64_ceiling_scale_int (GST_SECOND, wav->fact, wav->rate);
1134     GST_INFO_OBJECT (wav, "Got duration (fact) %" GST_TIME_FORMAT,
1135         GST_TIME_ARGS (wav->duration));
1136     return TRUE;
1137   }
1138   return FALSE;
1139 }
1140
1141 static gboolean
1142 gst_waveparse_ignore_chunk (GstWavParse * wav, GstBuffer * buf, guint32 tag,
1143     guint32 size)
1144 {
1145   guint flush;
1146
1147   if (wav->streaming) {
1148     if (!gst_wavparse_peek_chunk (wav, &tag, &size))
1149       return FALSE;
1150   }
1151   GST_DEBUG_OBJECT (wav, "Ignoring tag %" GST_FOURCC_FORMAT,
1152       GST_FOURCC_ARGS (tag));
1153   flush = 8 + ((size + 1) & ~1);
1154   wav->offset += flush;
1155   if (wav->streaming) {
1156     gst_adapter_flush (wav->adapter, flush);
1157   } else {
1158     gst_buffer_unref (buf);
1159   }
1160
1161   return TRUE;
1162 }
1163
1164 #define MAX_BUFFER_SIZE 4096
1165
1166 static GstFlowReturn
1167 gst_wavparse_stream_headers (GstWavParse * wav)
1168 {
1169   GstFlowReturn res = GST_FLOW_OK;
1170   GstBuffer *buf = NULL;
1171   gst_riff_strf_auds *header = NULL;
1172   guint32 tag, size;
1173   gboolean gotdata = FALSE;
1174   GstCaps *caps = NULL;
1175   gchar *codec_name = NULL;
1176   GstEvent **event_p;
1177   GstFormat bformat;
1178   gint64 upstream_size = 0;
1179
1180   /* search for "_fmt" chunk, which should be first */
1181   while (!wav->got_fmt) {
1182     GstBuffer *extra;
1183
1184     /* The header starts with a 'fmt ' tag */
1185     if (wav->streaming) {
1186       if (!gst_wavparse_peek_chunk (wav, &tag, &size))
1187         return res;
1188
1189       gst_adapter_flush (wav->adapter, 8);
1190       wav->offset += 8;
1191
1192       if (size) {
1193         buf = gst_adapter_take_buffer (wav->adapter, size);
1194         if (size & 1)
1195           gst_adapter_flush (wav->adapter, 1);
1196         wav->offset += GST_ROUND_UP_2 (size);
1197       } else {
1198         buf = gst_buffer_new ();
1199       }
1200     } else {
1201       if ((res = gst_riff_read_chunk (GST_ELEMENT_CAST (wav), wav->sinkpad,
1202                   &wav->offset, &tag, &buf)) != GST_FLOW_OK)
1203         return res;
1204     }
1205
1206     if (tag == GST_RIFF_TAG_JUNK || tag == GST_RIFF_TAG_JUNQ ||
1207         tag == GST_RIFF_TAG_bext || tag == GST_RIFF_TAG_BEXT ||
1208         tag == GST_RIFF_TAG_LIST || tag == GST_RIFF_TAG_ID32 ||
1209         tag == GST_RIFF_TAG_IDVX) {
1210       GST_DEBUG_OBJECT (wav, "skipping %" GST_FOURCC_FORMAT " chunk",
1211           GST_FOURCC_ARGS (tag));
1212       gst_buffer_unref (buf);
1213       buf = NULL;
1214       continue;
1215     }
1216
1217     if (tag != GST_RIFF_TAG_fmt)
1218       goto invalid_wav;
1219
1220     if (!(gst_riff_parse_strf_auds (GST_ELEMENT_CAST (wav), buf, &header,
1221                 &extra)))
1222       goto parse_header_error;
1223
1224     buf = NULL;                 /* parse_strf_auds() took ownership of buffer */
1225
1226     /* do sanity checks of header fields */
1227     if (header->channels == 0)
1228       goto no_channels;
1229     if (header->rate == 0)
1230       goto no_rate;
1231
1232     GST_DEBUG_OBJECT (wav, "creating the caps");
1233
1234     /* Note: gst_riff_create_audio_caps might need to fix values in
1235      * the header header depending on the format, so call it first */
1236     caps = gst_riff_create_audio_caps (header->format, NULL, header, extra,
1237         NULL, &codec_name);
1238
1239     if (extra)
1240       gst_buffer_unref (extra);
1241
1242     if (!caps)
1243       goto unknown_format;
1244
1245     /* do more sanity checks of header fields
1246      * (these can be sanitized by gst_riff_create_audio_caps()
1247      */
1248     wav->format = header->format;
1249     wav->rate = header->rate;
1250     wav->channels = header->channels;
1251     wav->blockalign = header->blockalign;
1252     wav->depth = header->size;
1253     wav->av_bps = header->av_bps;
1254     wav->vbr = FALSE;
1255
1256     g_free (header);
1257     header = NULL;
1258
1259     /* do format specific handling */
1260     switch (wav->format) {
1261       case GST_RIFF_WAVE_FORMAT_MPEGL12:
1262       case GST_RIFF_WAVE_FORMAT_MPEGL3:
1263       {
1264         /* Note: workaround for mp2/mp3 embedded in wav, that relies on the
1265          * bitrate inside the mpeg stream */
1266         GST_INFO ("resetting bps from %d to 0 for mp2/3", wav->av_bps);
1267         wav->bps = 0;
1268         break;
1269       }
1270       case GST_RIFF_WAVE_FORMAT_PCM:
1271         if (wav->blockalign > wav->channels * (guint) ceil (wav->depth / 8.0))
1272           goto invalid_blockalign;
1273         /* fall through */
1274       default:
1275         if (wav->av_bps > wav->blockalign * wav->rate)
1276           goto invalid_bps;
1277         /* use the configured bps */
1278         wav->bps = wav->av_bps;
1279         break;
1280     }
1281
1282     wav->width = (wav->blockalign * 8) / wav->channels;
1283     wav->bytes_per_sample = wav->channels * wav->width / 8;
1284
1285     if (wav->bytes_per_sample <= 0)
1286       goto no_bytes_per_sample;
1287
1288     GST_DEBUG_OBJECT (wav, "blockalign = %u", (guint) wav->blockalign);
1289     GST_DEBUG_OBJECT (wav, "width      = %u", (guint) wav->width);
1290     GST_DEBUG_OBJECT (wav, "depth      = %u", (guint) wav->depth);
1291     GST_DEBUG_OBJECT (wav, "av_bps     = %u", (guint) wav->av_bps);
1292     GST_DEBUG_OBJECT (wav, "frequency  = %u", (guint) wav->rate);
1293     GST_DEBUG_OBJECT (wav, "channels   = %u", (guint) wav->channels);
1294     GST_DEBUG_OBJECT (wav, "bytes_per_sample = %u", wav->bytes_per_sample);
1295
1296     /* bps can be 0 when we don't have a valid bitrate (mostly for compressed
1297      * formats). This will make the element output a BYTE format segment and
1298      * will not timestamp the outgoing buffers.
1299      */
1300     GST_DEBUG_OBJECT (wav, "bps        = %u", (guint) wav->bps);
1301
1302     GST_DEBUG_OBJECT (wav, "caps = %" GST_PTR_FORMAT, caps);
1303
1304     /* create pad later so we can sniff the first few bytes
1305      * of the real data and correct our caps if necessary */
1306     gst_caps_replace (&wav->caps, caps);
1307     gst_caps_replace (&caps, NULL);
1308
1309     wav->got_fmt = TRUE;
1310
1311     if (codec_name) {
1312       wav->tags = gst_tag_list_new ();
1313
1314       gst_tag_list_add (wav->tags, GST_TAG_MERGE_REPLACE,
1315           GST_TAG_AUDIO_CODEC, codec_name, NULL);
1316 #ifdef WAVPARSER_MODIFICATION
1317       gst_tag_list_add (wav->tags, GST_TAG_MERGE_REPLACE,
1318           GST_TAG_BITRATE, (guint)(wav->av_bps*8), NULL); // bitrate
1319 #endif
1320       g_free (codec_name);
1321       codec_name = NULL;
1322     }
1323
1324   }
1325
1326   bformat = GST_FORMAT_BYTES;
1327   gst_pad_query_peer_duration (wav->sinkpad, &bformat, &upstream_size);
1328   GST_DEBUG_OBJECT (wav, "upstream size %" G_GUINT64_FORMAT, upstream_size);
1329
1330   /* loop headers until we get data */
1331   while (!gotdata) {
1332     if (wav->streaming) {
1333       if (!gst_wavparse_peek_chunk_info (wav, &tag, &size))
1334         goto exit;
1335     } else {
1336       if ((res =
1337               gst_pad_pull_range (wav->sinkpad, wav->offset, 8,
1338                   &buf)) != GST_FLOW_OK)
1339         goto header_read_error;
1340       tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf));
1341       size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 4);
1342     }
1343
1344     GST_INFO_OBJECT (wav,
1345         "Got TAG: %" GST_FOURCC_FORMAT ", offset %" G_GUINT64_FORMAT,
1346         GST_FOURCC_ARGS (tag), wav->offset);
1347
1348     /* wav is a st00pid format, we don't know for sure where data starts.
1349      * So we have to go bit by bit until we find the 'data' header
1350      */
1351     switch (tag) {
1352       case GST_RIFF_TAG_data:{
1353         GST_DEBUG_OBJECT (wav, "Got 'data' TAG, size : %d", size);
1354         if (wav->streaming) {
1355           gst_adapter_flush (wav->adapter, 8);
1356           gotdata = TRUE;
1357         } else {
1358           gst_buffer_unref (buf);
1359         }
1360         wav->offset += 8;
1361         wav->datastart = wav->offset;
1362         /* If size is zero, then the data chunk probably actually extends to
1363            the end of the file */
1364         if (size == 0 && upstream_size) {
1365           size = upstream_size - wav->datastart;
1366         }
1367         /* Or the file might be truncated */
1368         else if (upstream_size) {
1369           size = MIN (size, (upstream_size - wav->datastart));
1370         }
1371         wav->datasize = (guint64) size;
1372         wav->dataleft = (guint64) size;
1373         wav->end_offset = size + wav->datastart;
1374         if (!wav->streaming) {
1375           /* We will continue parsing tags 'till end */
1376           wav->offset += size;
1377         }
1378         GST_DEBUG_OBJECT (wav, "datasize = %d", size);
1379         break;
1380       }
1381       case GST_RIFF_TAG_fact:{
1382         if (wav->format != GST_RIFF_WAVE_FORMAT_MPEGL12 &&
1383             wav->format != GST_RIFF_WAVE_FORMAT_MPEGL3) {
1384           const guint data_size = 4;
1385
1386           GST_INFO_OBJECT (wav, "Have fact chunk");
1387           if (size < data_size) {
1388             if (!gst_waveparse_ignore_chunk (wav, buf, tag, size)) {
1389               /* need more data */
1390               goto exit;
1391             }
1392             GST_DEBUG_OBJECT (wav, "need %d, available %d; ignoring chunk",
1393                 data_size, size);
1394             break;
1395           }
1396           /* number of samples (for compressed formats) */
1397           if (wav->streaming) {
1398             const guint8 *data = NULL;
1399
1400             if (!gst_wavparse_peek_chunk (wav, &tag, &size)) {
1401               goto exit;
1402             }
1403             gst_adapter_flush (wav->adapter, 8);
1404             data = gst_adapter_peek (wav->adapter, data_size);
1405             wav->fact = GST_READ_UINT32_LE (data);
1406             gst_adapter_flush (wav->adapter, GST_ROUND_UP_2 (size));
1407           } else {
1408             gst_buffer_unref (buf);
1409             if ((res =
1410                     gst_pad_pull_range (wav->sinkpad, wav->offset + 8,
1411                         data_size, &buf)) != GST_FLOW_OK)
1412               goto header_read_error;
1413             wav->fact = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf));
1414             gst_buffer_unref (buf);
1415           }
1416           GST_DEBUG_OBJECT (wav, "have fact %u", wav->fact);
1417           wav->offset += 8 + GST_ROUND_UP_2 (size);
1418           break;
1419         } else {
1420           if (!gst_waveparse_ignore_chunk (wav, buf, tag, size)) {
1421             /* need more data */
1422             goto exit;
1423           }
1424         }
1425         break;
1426       }
1427       case GST_RIFF_TAG_acid:{
1428         const gst_riff_acid *acid = NULL;
1429         const guint data_size = sizeof (gst_riff_acid);
1430
1431         GST_INFO_OBJECT (wav, "Have acid chunk");
1432         if (size < data_size) {
1433           if (!gst_waveparse_ignore_chunk (wav, buf, tag, size)) {
1434             /* need more data */
1435             goto exit;
1436           }
1437           GST_DEBUG_OBJECT (wav, "need %d, available %d; ignoring chunk",
1438               data_size, size);
1439           break;
1440         }
1441         if (wav->streaming) {
1442           if (!gst_wavparse_peek_chunk (wav, &tag, &size)) {
1443             goto exit;
1444           }
1445           gst_adapter_flush (wav->adapter, 8);
1446           acid = (const gst_riff_acid *) gst_adapter_peek (wav->adapter,
1447               data_size);
1448         } else {
1449           gst_buffer_unref (buf);
1450           if ((res =
1451                   gst_pad_pull_range (wav->sinkpad, wav->offset + 8,
1452                       size, &buf)) != GST_FLOW_OK)
1453             goto header_read_error;
1454           acid = (const gst_riff_acid *) GST_BUFFER_DATA (buf);
1455         }
1456         /* send data as tags */
1457         if (!wav->tags)
1458           wav->tags = gst_tag_list_new ();
1459         gst_tag_list_add (wav->tags, GST_TAG_MERGE_REPLACE,
1460             GST_TAG_BEATS_PER_MINUTE, acid->tempo, NULL);
1461
1462         size = GST_ROUND_UP_2 (size);
1463         if (wav->streaming) {
1464           gst_adapter_flush (wav->adapter, size);
1465         } else {
1466           gst_buffer_unref (buf);
1467         }
1468         wav->offset += 8 + size;
1469         break;
1470       }
1471         /* FIXME: all list tags after data are ignored in streaming mode */
1472       case GST_RIFF_TAG_LIST:{
1473         guint32 ltag;
1474
1475         if (wav->streaming) {
1476           const guint8 *data = NULL;
1477
1478           if (gst_adapter_available (wav->adapter) < 12) {
1479             goto exit;
1480           }
1481           data = gst_adapter_peek (wav->adapter, 12);
1482           ltag = GST_READ_UINT32_LE (data + 8);
1483         } else {
1484           gst_buffer_unref (buf);
1485           if ((res =
1486                   gst_pad_pull_range (wav->sinkpad, wav->offset, 12,
1487                       &buf)) != GST_FLOW_OK)
1488             goto header_read_error;
1489           ltag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 8);
1490         }
1491         switch (ltag) {
1492           case GST_RIFF_LIST_INFO:{
1493             const gint data_size = size - 4;
1494             GstTagList *new;
1495
1496             GST_INFO_OBJECT (wav, "Have LIST chunk INFO size %u", data_size);
1497             if (wav->streaming) {
1498               if (!gst_wavparse_peek_chunk (wav, &tag, &size)) {
1499                 goto exit;
1500               }
1501               gst_adapter_flush (wav->adapter, 12);
1502               wav->offset += 12;
1503               if (data_size > 0) {
1504                 buf = gst_adapter_take_buffer (wav->adapter, data_size);
1505                 if (data_size & 1)
1506                   gst_adapter_flush (wav->adapter, 1);
1507               }
1508             } else {
1509               wav->offset += 12;
1510               gst_buffer_unref (buf);
1511               if (data_size > 0) {
1512                 if ((res =
1513                         gst_pad_pull_range (wav->sinkpad, wav->offset,
1514                             data_size, &buf)) != GST_FLOW_OK)
1515                   goto header_read_error;
1516               }
1517             }
1518             if (data_size > 0) {
1519               /* parse tags */
1520               gst_riff_parse_info (GST_ELEMENT (wav), buf, &new);
1521               if (new) {
1522                 GstTagList *old = wav->tags;
1523                 wav->tags =
1524                     gst_tag_list_merge (old, new, GST_TAG_MERGE_REPLACE);
1525                 if (old)
1526                   gst_tag_list_free (old);
1527                 gst_tag_list_free (new);
1528               }
1529               gst_buffer_unref (buf);
1530               wav->offset += GST_ROUND_UP_2 (data_size);
1531             }
1532             break;
1533           }
1534           default:
1535             GST_INFO_OBJECT (wav, "Ignoring LIST chunk %" GST_FOURCC_FORMAT,
1536                 GST_FOURCC_ARGS (ltag));
1537             if (!gst_waveparse_ignore_chunk (wav, buf, tag, size))
1538               /* need more data */
1539               goto exit;
1540             break;
1541         }
1542         break;
1543       }
1544       default:
1545         if (!gst_waveparse_ignore_chunk (wav, buf, tag, size))
1546           /* need more data */
1547           goto exit;
1548         break;
1549     }
1550
1551     if (upstream_size && (wav->offset >= upstream_size)) {
1552       /* Now we are gone through the whole file */
1553       gotdata = TRUE;
1554     }
1555   }
1556
1557   GST_DEBUG_OBJECT (wav, "Finished parsing headers");
1558
1559   if (wav->bps <= 0 && wav->fact) {
1560 #if 0
1561     /* not a good idea, as for embedded mp2/mp3 we set bps to 0 earlier */
1562     wav->bps =
1563         (guint32) gst_util_uint64_scale ((guint64) wav->rate, wav->datasize,
1564         (guint64) wav->fact);
1565     GST_INFO_OBJECT (wav, "calculated bps : %d, enabling VBR", wav->bps);
1566 #endif
1567     wav->vbr = TRUE;
1568   }
1569
1570   if (gst_wavparse_calculate_duration (wav)) {
1571     gst_segment_init (&wav->segment, GST_FORMAT_TIME);
1572     gst_segment_set_duration (&wav->segment, GST_FORMAT_TIME, wav->duration);
1573   } else {
1574     /* no bitrate, let downstream peer do the math, we'll feed it bytes. */
1575     gst_segment_init (&wav->segment, GST_FORMAT_BYTES);
1576     gst_segment_set_duration (&wav->segment, GST_FORMAT_BYTES, wav->datasize);
1577   }
1578
1579   /* now we have all the info to perform a pending seek if any, if no
1580    * event, this will still do the right thing and it will also send
1581    * the right newsegment event downstream. */
1582   gst_wavparse_perform_seek (wav, wav->seek_event);
1583   /* remove pending event */
1584   event_p = &wav->seek_event;
1585   gst_event_replace (event_p, NULL);
1586
1587   /* we just started, we are discont */
1588   wav->discont = TRUE;
1589
1590   wav->state = GST_WAVPARSE_DATA;
1591
1592   /* determine reasonable max buffer size,
1593    * that is, buffers not too small either size or time wise
1594    * so we do not end up with too many of them */
1595   /* var abuse */
1596   upstream_size = 0;
1597   gst_wavparse_time_to_bytepos (wav, 40 * GST_MSECOND, &upstream_size);
1598   wav->max_buf_size = upstream_size;
1599   wav->max_buf_size = MAX (wav->max_buf_size, MAX_BUFFER_SIZE);
1600   if (wav->blockalign > 0)
1601     wav->max_buf_size -= (wav->max_buf_size % wav->blockalign);
1602
1603   GST_DEBUG_OBJECT (wav, "max buffer size %d", wav->max_buf_size);
1604
1605   return GST_FLOW_OK;
1606
1607   /* ERROR */
1608 exit:
1609   {
1610     if (codec_name)
1611       g_free (codec_name);
1612     if (header)
1613       g_free (header);
1614     if (caps)
1615       gst_caps_unref (caps);
1616     return res;
1617   }
1618 fail:
1619   {
1620     res = GST_FLOW_ERROR;
1621     goto exit;
1622   }
1623 invalid_wav:
1624   {
1625     GST_ELEMENT_ERROR (wav, STREAM, TYPE_NOT_FOUND, (NULL),
1626         ("Invalid WAV header (no fmt at start): %"
1627             GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
1628     goto fail;
1629   }
1630 parse_header_error:
1631   {
1632     GST_ELEMENT_ERROR (wav, STREAM, DEMUX, (NULL),
1633         ("Couldn't parse audio header"));
1634     goto fail;
1635   }
1636 no_channels:
1637   {
1638     GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL),
1639         ("Stream claims to contain no channels - invalid data"));
1640     goto fail;
1641   }
1642 no_rate:
1643   {
1644     GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL),
1645         ("Stream with sample_rate == 0 - invalid data"));
1646     goto fail;
1647   }
1648 invalid_blockalign:
1649   {
1650     GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL),
1651         ("Stream claims blockalign = %u, which is more than %u - invalid data",
1652             wav->blockalign, wav->channels * (guint) ceil (wav->depth / 8.0)));
1653     goto fail;
1654   }
1655 invalid_bps:
1656   {
1657     GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL),
1658         ("Stream claims av_bsp = %u, which is more than %u - invalid data",
1659             wav->av_bps, wav->blockalign * wav->rate));
1660     goto fail;
1661   }
1662 no_bytes_per_sample:
1663   {
1664     GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL),
1665         ("Could not caluclate bytes per sample - invalid data"));
1666     goto fail;
1667   }
1668 unknown_format:
1669   {
1670     GST_ELEMENT_ERROR (wav, STREAM, TYPE_NOT_FOUND, (NULL),
1671         ("No caps found for format 0x%x, %d channels, %d Hz",
1672             wav->format, wav->channels, wav->rate));
1673     goto fail;
1674   }
1675 header_read_error:
1676   {
1677     GST_ELEMENT_ERROR (wav, STREAM, DEMUX, (NULL),
1678         ("Couldn't read in header %d (%s)", res, gst_flow_get_name (res)));
1679     goto fail;
1680   }
1681 }
1682
1683 /*
1684  * Read WAV file tag when streaming
1685  */
1686 static GstFlowReturn
1687 gst_wavparse_parse_stream_init (GstWavParse * wav)
1688 {
1689   if (gst_adapter_available (wav->adapter) >= 12) {
1690     GstBuffer *tmp;
1691
1692     /* _take flushes the data */
1693     tmp = gst_adapter_take_buffer (wav->adapter, 12);
1694
1695     GST_DEBUG ("Parsing wav header");
1696     if (!gst_wavparse_parse_file_header (GST_ELEMENT_CAST (wav), tmp))
1697       return GST_FLOW_ERROR;
1698
1699     wav->offset += 12;
1700     /* Go to next state */
1701     wav->state = GST_WAVPARSE_HEADER;
1702   }
1703   return GST_FLOW_OK;
1704 }
1705
1706 /* handle an event sent directly to the element.
1707  *
1708  * This event can be sent either in the READY state or the
1709  * >READY state. The only event of interest really is the seek
1710  * event.
1711  *
1712  * In the READY state we can only store the event and try to
1713  * respect it when going to PAUSED. We assume we are in the
1714  * READY state when our parsing state != GST_WAVPARSE_DATA.
1715  *
1716  * When we are steaming, we can simply perform the seek right
1717  * away.
1718  */
1719 static gboolean
1720 gst_wavparse_send_event (GstElement * element, GstEvent * event)
1721 {
1722   GstWavParse *wav = GST_WAVPARSE (element);
1723   gboolean res = FALSE;
1724   GstEvent **event_p;
1725
1726   GST_DEBUG_OBJECT (wav, "received event %s", GST_EVENT_TYPE_NAME (event));
1727
1728   switch (GST_EVENT_TYPE (event)) {
1729     case GST_EVENT_SEEK:
1730       if (wav->state == GST_WAVPARSE_DATA) {
1731         /* we can handle the seek directly when streaming data */
1732         res = gst_wavparse_perform_seek (wav, event);
1733       } else {
1734         GST_DEBUG_OBJECT (wav, "queuing seek for later");
1735
1736         event_p = &wav->seek_event;
1737         gst_event_replace (event_p, event);
1738
1739         /* we always return true */
1740         res = TRUE;
1741       }
1742       break;
1743     default:
1744       break;
1745   }
1746   gst_event_unref (event);
1747   return res;
1748 }
1749
1750 static gboolean
1751 gst_wavparse_have_dts_caps (const GstCaps * caps, GstTypeFindProbability prob)
1752 {
1753   GstStructure *s;
1754
1755   s = gst_caps_get_structure (caps, 0);
1756   if (!gst_structure_has_name (s, "audio/x-dts"))
1757     return FALSE;
1758   if (prob >= GST_TYPE_FIND_LIKELY)
1759     return TRUE;
1760   /* DTS at non-0 offsets and without second sync may yield POSSIBLE .. */
1761   if (prob < GST_TYPE_FIND_POSSIBLE)
1762     return FALSE;
1763   /* .. in which case we want at least a valid-looking rate and channels */
1764   if (!gst_structure_has_field (s, "channels"))
1765     return FALSE;
1766   /* and for extra assurance we could also check the rate from the DTS frame
1767    * against the one in the wav header, but for now let's not do that */
1768   return gst_structure_has_field (s, "rate");
1769 }
1770
1771 static void
1772 gst_wavparse_add_src_pad (GstWavParse * wav, GstBuffer * buf)
1773 {
1774   GstStructure *s;
1775
1776   GST_DEBUG_OBJECT (wav, "adding src pad");
1777
1778   if (wav->caps) {
1779     s = gst_caps_get_structure (wav->caps, 0);
1780     if (s && gst_structure_has_name (s, "audio/x-raw-int") && buf != NULL) {
1781       GstTypeFindProbability prob;
1782       GstCaps *tf_caps;
1783
1784       tf_caps = gst_type_find_helper_for_buffer (GST_OBJECT (wav), buf, &prob);
1785       if (tf_caps != NULL) {
1786         GST_LOG ("typefind caps = %" GST_PTR_FORMAT ", P=%d", tf_caps, prob);
1787         if (gst_wavparse_have_dts_caps (tf_caps, prob)) {
1788           GST_INFO_OBJECT (wav, "Found DTS marker in file marked as raw PCM");
1789           gst_caps_unref (wav->caps);
1790           wav->caps = tf_caps;
1791
1792           gst_tag_list_add (wav->tags, GST_TAG_MERGE_REPLACE,
1793               GST_TAG_AUDIO_CODEC, "dts", NULL);
1794         } else {
1795           GST_DEBUG_OBJECT (wav, "found caps %" GST_PTR_FORMAT " for stream "
1796               "marked as raw PCM audio, but ignoring for now", tf_caps);
1797           gst_caps_unref (tf_caps);
1798         }
1799       }
1800     }
1801   }
1802
1803   gst_wavparse_create_sourcepad (wav);
1804   gst_pad_set_active (wav->srcpad, TRUE);
1805   gst_pad_set_caps (wav->srcpad, wav->caps);
1806   gst_caps_replace (&wav->caps, NULL);
1807
1808   gst_element_add_pad (GST_ELEMENT_CAST (wav), wav->srcpad);
1809   gst_element_no_more_pads (GST_ELEMENT_CAST (wav));
1810
1811   if (wav->close_segment) {
1812     GST_DEBUG_OBJECT (wav, "Send close segment event on newpad");
1813     gst_pad_push_event (wav->srcpad, wav->close_segment);
1814     wav->close_segment = NULL;
1815   }
1816   if (wav->start_segment) {
1817     GST_DEBUG_OBJECT (wav, "Send start segment event on newpad");
1818     gst_pad_push_event (wav->srcpad, wav->start_segment);
1819     wav->start_segment = NULL;
1820   }
1821
1822   if (wav->tags) {
1823     gst_element_found_tags_for_pad (GST_ELEMENT_CAST (wav), wav->srcpad,
1824         wav->tags);
1825     wav->tags = NULL;
1826   }
1827 }
1828
1829 static GstFlowReturn
1830 gst_wavparse_stream_data (GstWavParse * wav)
1831 {
1832   GstBuffer *buf = NULL;
1833   GstFlowReturn res = GST_FLOW_OK;
1834   guint64 desired, obtained;
1835   GstClockTime timestamp, next_timestamp, duration;
1836   guint64 pos, nextpos;
1837
1838 iterate_adapter:
1839   GST_LOG_OBJECT (wav,
1840       "offset: %" G_GINT64_FORMAT " , end: %" G_GINT64_FORMAT " , dataleft: %"
1841       G_GINT64_FORMAT, wav->offset, wav->end_offset, wav->dataleft);
1842
1843   /* Get the next n bytes and output them */
1844   if (wav->dataleft == 0 || wav->dataleft < wav->blockalign)
1845     goto found_eos;
1846
1847   /* scale the amount of data by the segment rate so we get equal
1848    * amounts of data regardless of the playback rate */
1849   desired =
1850       MIN (gst_guint64_to_gdouble (wav->dataleft),
1851       wav->max_buf_size * wav->segment.abs_rate);
1852
1853   if (desired >= wav->blockalign && wav->blockalign > 0)
1854     desired -= (desired % wav->blockalign);
1855
1856   GST_LOG_OBJECT (wav, "Fetching %" G_GINT64_FORMAT " bytes of data "
1857       "from the sinkpad", desired);
1858
1859   if (wav->streaming) {
1860     guint avail = gst_adapter_available (wav->adapter);
1861     guint extra;
1862
1863     /* flush some bytes if evil upstream sends segment that starts
1864      * before data or does is not send sample aligned segment */
1865     if (G_LIKELY (wav->offset >= wav->datastart)) {
1866       extra = (wav->offset - wav->datastart) % wav->bytes_per_sample;
1867     } else {
1868       extra = wav->datastart - wav->offset;
1869     }
1870
1871     if (G_UNLIKELY (extra)) {
1872       extra = wav->bytes_per_sample - extra;
1873       if (extra <= avail) {
1874         GST_DEBUG_OBJECT (wav, "flushing %d bytes to sample boundary", extra);
1875         gst_adapter_flush (wav->adapter, extra);
1876         wav->offset += extra;
1877         wav->dataleft -= extra;
1878         goto iterate_adapter;
1879       } else {
1880         GST_DEBUG_OBJECT (wav, "flushing %d bytes", avail);
1881         gst_adapter_clear (wav->adapter);
1882         wav->offset += avail;
1883         wav->dataleft -= avail;
1884         return GST_FLOW_OK;
1885       }
1886     }
1887
1888     if (avail < desired) {
1889       GST_LOG_OBJECT (wav, "Got only %d bytes of data from the sinkpad", avail);
1890       return GST_FLOW_OK;
1891     }
1892
1893     buf = gst_adapter_take_buffer (wav->adapter, desired);
1894   } else {
1895     if ((res = gst_pad_pull_range (wav->sinkpad, wav->offset,
1896                 desired, &buf)) != GST_FLOW_OK)
1897       goto pull_error;
1898
1899     /* we may get a short buffer at the end of the file */
1900     if (GST_BUFFER_SIZE (buf) < desired) {
1901       GST_LOG_OBJECT (wav, "Got only %u bytes of data", GST_BUFFER_SIZE (buf));
1902       if (GST_BUFFER_SIZE (buf) >= wav->blockalign) {
1903         buf = gst_buffer_make_metadata_writable (buf);
1904         GST_BUFFER_SIZE (buf) -= (GST_BUFFER_SIZE (buf) % wav->blockalign);
1905       } else {
1906         gst_buffer_unref (buf);
1907         goto found_eos;
1908       }
1909     }
1910   }
1911
1912   obtained = GST_BUFFER_SIZE (buf);
1913
1914   /* our positions in bytes */
1915   pos = wav->offset - wav->datastart;
1916   nextpos = pos + obtained;
1917
1918   /* update offsets, does not overflow. */
1919   GST_BUFFER_OFFSET (buf) = pos / wav->bytes_per_sample;
1920   GST_BUFFER_OFFSET_END (buf) = nextpos / wav->bytes_per_sample;
1921
1922   /* first chunk of data? create the source pad. We do this only here so
1923    * we can detect broken .wav files with dts disguised as raw PCM (sigh) */
1924   if (G_UNLIKELY (wav->first)) {
1925     wav->first = FALSE;
1926     /* this will also push the segment events */
1927     gst_wavparse_add_src_pad (wav, buf);
1928   } else {
1929     /* If we have a pending close/start segment, send it now. */
1930     if (G_UNLIKELY (wav->close_segment != NULL)) {
1931       gst_pad_push_event (wav->srcpad, wav->close_segment);
1932       wav->close_segment = NULL;
1933     }
1934     if (G_UNLIKELY (wav->start_segment != NULL)) {
1935       gst_pad_push_event (wav->srcpad, wav->start_segment);
1936       wav->start_segment = NULL;
1937     }
1938   }
1939
1940   if (wav->bps > 0) {
1941     /* and timestamps if we have a bitrate, be careful for overflows */
1942     timestamp = uint64_ceiling_scale (pos, GST_SECOND, (guint64) wav->bps);
1943     next_timestamp =
1944         uint64_ceiling_scale (nextpos, GST_SECOND, (guint64) wav->bps);
1945     duration = next_timestamp - timestamp;
1946
1947     /* update current running segment position */
1948     if (G_LIKELY (next_timestamp >= wav->segment.start))
1949       gst_segment_set_last_stop (&wav->segment, GST_FORMAT_TIME,
1950           next_timestamp);
1951   } else if (wav->fact) {
1952     guint64 bps =
1953         gst_util_uint64_scale_int (wav->datasize, wav->rate, wav->fact);
1954     /* and timestamps if we have a bitrate, be careful for overflows */
1955     timestamp = uint64_ceiling_scale (pos, GST_SECOND, bps);
1956     next_timestamp = uint64_ceiling_scale (nextpos, GST_SECOND, bps);
1957     duration = next_timestamp - timestamp;
1958   } else {
1959     /* no bitrate, all we know is that the first sample has timestamp 0, all
1960      * other positions and durations have unknown timestamp. */
1961     if (pos == 0)
1962       timestamp = 0;
1963     else
1964       timestamp = GST_CLOCK_TIME_NONE;
1965     duration = GST_CLOCK_TIME_NONE;
1966     /* update current running segment position with byte offset */
1967     if (G_LIKELY (nextpos >= wav->segment.start))
1968       gst_segment_set_last_stop (&wav->segment, GST_FORMAT_BYTES, nextpos);
1969   }
1970   if ((pos > 0) && wav->vbr) {
1971     /* don't set timestamps for VBR files if it's not the first buffer */
1972     timestamp = GST_CLOCK_TIME_NONE;
1973     duration = GST_CLOCK_TIME_NONE;
1974   }
1975   if (wav->discont) {
1976     GST_DEBUG_OBJECT (wav, "marking DISCONT");
1977     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
1978     wav->discont = FALSE;
1979   }
1980
1981   GST_BUFFER_TIMESTAMP (buf) = timestamp;
1982   GST_BUFFER_DURATION (buf) = duration;
1983
1984   /* don't forget to set the caps on the buffer */
1985   gst_buffer_set_caps (buf, GST_PAD_CAPS (wav->srcpad));
1986
1987   GST_LOG_OBJECT (wav,
1988       "Got buffer. timestamp:%" GST_TIME_FORMAT " , duration:%" GST_TIME_FORMAT
1989       ", size:%u", GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration),
1990       GST_BUFFER_SIZE (buf));
1991
1992   if ((res = gst_pad_push (wav->srcpad, buf)) != GST_FLOW_OK)
1993     goto push_error;
1994
1995   if (obtained < wav->dataleft) {
1996     wav->offset += obtained;
1997     wav->dataleft -= obtained;
1998   } else {
1999     wav->offset += wav->dataleft;
2000     wav->dataleft = 0;
2001   }
2002
2003   /* Iterate until need more data, so adapter size won't grow */
2004   if (wav->streaming) {
2005     GST_LOG_OBJECT (wav,
2006         "offset: %" G_GINT64_FORMAT " , end: %" G_GINT64_FORMAT, wav->offset,
2007         wav->end_offset);
2008     goto iterate_adapter;
2009   }
2010   return res;
2011
2012   /* ERROR */
2013 found_eos:
2014   {
2015     GST_DEBUG_OBJECT (wav, "found EOS");
2016     return GST_FLOW_UNEXPECTED;
2017   }
2018 pull_error:
2019   {
2020     /* check if we got EOS */
2021     if (res == GST_FLOW_UNEXPECTED)
2022       goto found_eos;
2023
2024     GST_WARNING_OBJECT (wav,
2025         "Error getting %" G_GINT64_FORMAT " bytes from the "
2026         "sinkpad (dataleft = %" G_GINT64_FORMAT ")", desired, wav->dataleft);
2027     return res;
2028   }
2029 push_error:
2030   {
2031     GST_INFO_OBJECT (wav,
2032         "Error pushing on srcpad %s:%s, reason %s, is linked? = %d",
2033         GST_DEBUG_PAD_NAME (wav->srcpad), gst_flow_get_name (res),
2034         gst_pad_is_linked (wav->srcpad));
2035     return res;
2036   }
2037 }
2038
2039 static void
2040 gst_wavparse_loop (GstPad * pad)
2041 {
2042   GstFlowReturn ret;
2043   GstWavParse *wav = GST_WAVPARSE (GST_PAD_PARENT (pad));
2044
2045   GST_LOG_OBJECT (wav, "process data");
2046
2047   switch (wav->state) {
2048     case GST_WAVPARSE_START:
2049       GST_INFO_OBJECT (wav, "GST_WAVPARSE_START");
2050       if ((ret = gst_wavparse_stream_init (wav)) != GST_FLOW_OK)
2051         goto pause;
2052
2053       wav->state = GST_WAVPARSE_HEADER;
2054       /* fall-through */
2055
2056     case GST_WAVPARSE_HEADER:
2057       GST_INFO_OBJECT (wav, "GST_WAVPARSE_HEADER");
2058       if ((ret = gst_wavparse_stream_headers (wav)) != GST_FLOW_OK)
2059         goto pause;
2060
2061       wav->state = GST_WAVPARSE_DATA;
2062       GST_INFO_OBJECT (wav, "GST_WAVPARSE_DATA");
2063       /* fall-through */
2064
2065     case GST_WAVPARSE_DATA:
2066       if ((ret = gst_wavparse_stream_data (wav)) != GST_FLOW_OK)
2067         goto pause;
2068       break;
2069     default:
2070       g_assert_not_reached ();
2071   }
2072   return;
2073
2074   /* ERRORS */
2075 pause:
2076   {
2077     const gchar *reason = gst_flow_get_name (ret);
2078
2079     GST_DEBUG_OBJECT (wav, "pausing task, reason %s", reason);
2080     wav->segment_running = FALSE;
2081     gst_pad_pause_task (pad);
2082
2083     if (ret == GST_FLOW_UNEXPECTED) {
2084       /* add pad before we perform EOS */
2085       if (G_UNLIKELY (wav->first)) {
2086         wav->first = FALSE;
2087         gst_wavparse_add_src_pad (wav, NULL);
2088       }
2089
2090       if (wav->state == GST_WAVPARSE_START)
2091         GST_ELEMENT_ERROR (wav, STREAM, WRONG_TYPE,
2092             ("No valid input found before end of stream"), (NULL));
2093
2094       /* perform EOS logic */
2095       if (wav->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2096         GstClockTime stop;
2097
2098         if ((stop = wav->segment.stop) == -1)
2099           stop = wav->segment.duration;
2100
2101         gst_element_post_message (GST_ELEMENT_CAST (wav),
2102             gst_message_new_segment_done (GST_OBJECT_CAST (wav),
2103                 wav->segment.format, stop));
2104       } else {
2105         if (wav->srcpad != NULL)
2106           gst_pad_push_event (wav->srcpad, gst_event_new_eos ());
2107       }
2108     } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_UNEXPECTED) {
2109       /* for fatal errors we post an error message, post the error
2110        * first so the app knows about the error first. */
2111       GST_ELEMENT_ERROR (wav, STREAM, FAILED,
2112           (_("Internal data flow error.")),
2113           ("streaming task paused, reason %s (%d)", reason, ret));
2114       if (wav->srcpad != NULL)
2115         gst_pad_push_event (wav->srcpad, gst_event_new_eos ());
2116     }
2117     return;
2118   }
2119 }
2120
2121 static GstFlowReturn
2122 gst_wavparse_chain (GstPad * pad, GstBuffer * buf)
2123 {
2124   GstFlowReturn ret;
2125   GstWavParse *wav = GST_WAVPARSE (GST_PAD_PARENT (pad));
2126
2127   GST_LOG_OBJECT (wav, "adapter_push %u bytes", GST_BUFFER_SIZE (buf));
2128
2129   gst_adapter_push (wav->adapter, buf);
2130
2131   switch (wav->state) {
2132     case GST_WAVPARSE_START:
2133       GST_INFO_OBJECT (wav, "GST_WAVPARSE_START");
2134       if ((ret = gst_wavparse_parse_stream_init (wav)) != GST_FLOW_OK)
2135         goto done;
2136
2137       if (wav->state != GST_WAVPARSE_HEADER)
2138         break;
2139
2140       /* otherwise fall-through */
2141     case GST_WAVPARSE_HEADER:
2142       GST_INFO_OBJECT (wav, "GST_WAVPARSE_HEADER");
2143       if ((ret = gst_wavparse_stream_headers (wav)) != GST_FLOW_OK)
2144         goto done;
2145
2146       if (!wav->got_fmt || wav->datastart == 0)
2147         break;
2148
2149       wav->state = GST_WAVPARSE_DATA;
2150       GST_INFO_OBJECT (wav, "GST_WAVPARSE_DATA");
2151
2152       /* fall-through */
2153     case GST_WAVPARSE_DATA:
2154       if (buf && GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT))
2155         wav->discont = TRUE;
2156       if ((ret = gst_wavparse_stream_data (wav)) != GST_FLOW_OK)
2157         goto done;
2158       break;
2159     default:
2160       g_return_val_if_reached (GST_FLOW_ERROR);
2161   }
2162 done:
2163   if (G_UNLIKELY (wav->abort_buffering)) {
2164     wav->abort_buffering = FALSE;
2165     ret = GST_FLOW_ERROR;
2166     /* sort of demux/parse error */
2167     GST_ELEMENT_ERROR (wav, STREAM, DEMUX, (NULL), ("unhandled buffer size"));
2168   }
2169
2170   return ret;
2171 }
2172
2173 static GstFlowReturn
2174 gst_wavparse_flush_data (GstWavParse * wav)
2175 {
2176   GstFlowReturn ret = GST_FLOW_OK;
2177   guint av;
2178
2179   if ((av = gst_adapter_available (wav->adapter)) > 0) {
2180     wav->dataleft = av;
2181     wav->end_offset = wav->offset + av;
2182     ret = gst_wavparse_stream_data (wav);
2183   }
2184
2185   return ret;
2186 }
2187
2188 static gboolean
2189 gst_wavparse_sink_event (GstPad * pad, GstEvent * event)
2190 {
2191   GstWavParse *wav = GST_WAVPARSE (GST_PAD_PARENT (pad));
2192   gboolean ret = TRUE;
2193
2194   GST_LOG_OBJECT (wav, "handling %s event", GST_EVENT_TYPE_NAME (event));
2195
2196   switch (GST_EVENT_TYPE (event)) {
2197     case GST_EVENT_NEWSEGMENT:
2198     {
2199       GstFormat format;
2200       gdouble rate, arate;
2201       gint64 start, stop, time, offset = 0, end_offset = -1;
2202       gboolean update;
2203       GstSegment segment;
2204
2205       /* some debug output */
2206       gst_segment_init (&segment, GST_FORMAT_UNDEFINED);
2207       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
2208           &start, &stop, &time);
2209       gst_segment_set_newsegment_full (&segment, update, rate, arate, format,
2210           start, stop, time);
2211       GST_DEBUG_OBJECT (wav,
2212           "received format %d newsegment %" GST_SEGMENT_FORMAT, format,
2213           &segment);
2214
2215       if (wav->state != GST_WAVPARSE_DATA) {
2216         GST_DEBUG_OBJECT (wav, "still starting, eating event");
2217         goto exit;
2218       }
2219
2220       /* now we are either committed to TIME or BYTE format,
2221        * and we only expect a BYTE segment, e.g. following a seek */
2222       if (format == GST_FORMAT_BYTES) {
2223         if (start > 0) {
2224           offset = start;
2225           start -= wav->datastart;
2226           start = MAX (start, 0);
2227         }
2228         if (stop > 0) {
2229           end_offset = stop;
2230           stop -= wav->datastart;
2231           stop = MAX (stop, 0);
2232         }
2233         if (wav->segment.format == GST_FORMAT_TIME) {
2234           guint64 bps = wav->bps;
2235
2236           /* operating in format TIME, so we can convert */
2237           if (!bps && wav->fact)
2238             bps =
2239                 gst_util_uint64_scale_int (wav->datasize, wav->rate, wav->fact);
2240           if (bps) {
2241             if (start >= 0)
2242               start =
2243                   uint64_ceiling_scale (start, GST_SECOND, (guint64) wav->bps);
2244             if (stop >= 0)
2245               stop =
2246                   uint64_ceiling_scale (stop, GST_SECOND, (guint64) wav->bps);
2247           }
2248         }
2249       } else {
2250         GST_DEBUG_OBJECT (wav, "unsupported segment format, ignoring");
2251         goto exit;
2252       }
2253
2254       /* accept upstream's notion of segment and distribute along */
2255       gst_segment_set_newsegment_full (&wav->segment, update, rate, arate,
2256           wav->segment.format, start, stop, start);
2257       /* also store the newsegment event for the streaming thread */
2258       if (wav->start_segment)
2259         gst_event_unref (wav->start_segment);
2260       wav->start_segment =
2261           gst_event_new_new_segment_full (update, rate, arate,
2262           wav->segment.format, start, stop, start);
2263       GST_DEBUG_OBJECT (wav, "Pushing newseg update %d, rate %g, "
2264           "applied rate %g, format %d, start %" G_GINT64_FORMAT ", "
2265           "stop %" G_GINT64_FORMAT, update, rate, arate, wav->segment.format,
2266           start, stop);
2267
2268       /* stream leftover data in current segment */
2269       gst_wavparse_flush_data (wav);
2270       /* and set up streaming thread for next one */
2271       wav->offset = offset;
2272       wav->end_offset = end_offset;
2273       if (wav->end_offset > 0) {
2274         wav->dataleft = wav->end_offset - wav->offset;
2275       } else {
2276         /* infinity; upstream will EOS when done */
2277         wav->dataleft = G_MAXUINT64;
2278       }
2279     exit:
2280       gst_event_unref (event);
2281       break;
2282     }
2283     case GST_EVENT_EOS:
2284       /* add pad if needed so EOS is seen downstream */
2285       if (G_UNLIKELY (wav->first)) {
2286         wav->first = FALSE;
2287         gst_wavparse_add_src_pad (wav, NULL);
2288       } else {
2289         /* stream leftover data in current segment */
2290         gst_wavparse_flush_data (wav);
2291       }
2292
2293       if (wav->state == GST_WAVPARSE_START)
2294         GST_ELEMENT_ERROR (wav, STREAM, WRONG_TYPE,
2295             ("No valid input found before end of stream"), (NULL));
2296
2297       /* fall-through */
2298     case GST_EVENT_FLUSH_STOP:
2299       gst_adapter_clear (wav->adapter);
2300       wav->discont = TRUE;
2301       /* fall-through */
2302     default:
2303       ret = gst_pad_event_default (wav->sinkpad, event);
2304       break;
2305   }
2306
2307   return ret;
2308 }
2309
2310 #if 0
2311 /* convert and query stuff */
2312 static const GstFormat *
2313 gst_wavparse_get_formats (GstPad * pad)
2314 {
2315   static GstFormat formats[] = {
2316     GST_FORMAT_TIME,
2317     GST_FORMAT_BYTES,
2318     GST_FORMAT_DEFAULT,         /* a "frame", ie a set of samples per Hz */
2319     0
2320   };
2321
2322   return formats;
2323 }
2324 #endif
2325
2326 static gboolean
2327 gst_wavparse_pad_convert (GstPad * pad,
2328     GstFormat src_format, gint64 src_value,
2329     GstFormat * dest_format, gint64 * dest_value)
2330 {
2331   GstWavParse *wavparse;
2332   gboolean res = TRUE;
2333
2334   wavparse = GST_WAVPARSE (GST_PAD_PARENT (pad));
2335
2336   if (*dest_format == src_format) {
2337     *dest_value = src_value;
2338     return TRUE;
2339   }
2340
2341   if ((wavparse->bps == 0) && !wavparse->fact)
2342     goto no_bps_fact;
2343
2344   GST_INFO_OBJECT (wavparse, "converting value from %s to %s",
2345       gst_format_get_name (src_format), gst_format_get_name (*dest_format));
2346
2347   switch (src_format) {
2348     case GST_FORMAT_BYTES:
2349       switch (*dest_format) {
2350         case GST_FORMAT_DEFAULT:
2351           *dest_value = src_value / wavparse->bytes_per_sample;
2352           /* make sure we end up on a sample boundary */
2353           *dest_value -= *dest_value % wavparse->bytes_per_sample;
2354           break;
2355         case GST_FORMAT_TIME:
2356           /* src_value + datastart = offset */
2357           GST_INFO_OBJECT (wavparse,
2358               "src=%" G_GINT64_FORMAT ", offset=%" G_GINT64_FORMAT, src_value,
2359               wavparse->offset);
2360           if (wavparse->bps > 0)
2361             *dest_value = uint64_ceiling_scale (src_value, GST_SECOND,
2362                 (guint64) wavparse->bps);
2363           else if (wavparse->fact) {
2364             guint64 bps = uint64_ceiling_scale_int (wavparse->datasize,
2365                 wavparse->rate, wavparse->fact);
2366
2367             *dest_value = uint64_ceiling_scale_int (src_value, GST_SECOND, bps);
2368           } else {
2369             res = FALSE;
2370           }
2371           break;
2372         default:
2373           res = FALSE;
2374           goto done;
2375       }
2376       break;
2377
2378     case GST_FORMAT_DEFAULT:
2379       switch (*dest_format) {
2380         case GST_FORMAT_BYTES:
2381           *dest_value = src_value * wavparse->bytes_per_sample;
2382           break;
2383         case GST_FORMAT_TIME:
2384           *dest_value = gst_util_uint64_scale (src_value, GST_SECOND,
2385               (guint64) wavparse->rate);
2386           break;
2387         default:
2388           res = FALSE;
2389           goto done;
2390       }
2391       break;
2392
2393     case GST_FORMAT_TIME:
2394       switch (*dest_format) {
2395         case GST_FORMAT_BYTES:
2396           if (wavparse->bps > 0)
2397             *dest_value = gst_util_uint64_scale (src_value,
2398                 (guint64) wavparse->bps, GST_SECOND);
2399           else {
2400             guint64 bps = gst_util_uint64_scale_int (wavparse->datasize,
2401                 wavparse->rate, wavparse->fact);
2402
2403             *dest_value = gst_util_uint64_scale (src_value, bps, GST_SECOND);
2404           }
2405           /* make sure we end up on a sample boundary */
2406           *dest_value -= *dest_value % wavparse->blockalign;
2407           break;
2408         case GST_FORMAT_DEFAULT:
2409           *dest_value = gst_util_uint64_scale (src_value,
2410               (guint64) wavparse->rate, GST_SECOND);
2411           break;
2412         default:
2413           res = FALSE;
2414           goto done;
2415       }
2416       break;
2417
2418     default:
2419       res = FALSE;
2420       goto done;
2421   }
2422
2423 done:
2424   return res;
2425
2426   /* ERRORS */
2427 no_bps_fact:
2428   {
2429     GST_DEBUG_OBJECT (wavparse, "bps 0 or no fact chunk, cannot convert");
2430     res = FALSE;
2431     goto done;
2432   }
2433 }
2434
2435 static const GstQueryType *
2436 gst_wavparse_get_query_types (GstPad * pad)
2437 {
2438   static const GstQueryType types[] = {
2439     GST_QUERY_POSITION,
2440     GST_QUERY_DURATION,
2441     GST_QUERY_CONVERT,
2442     GST_QUERY_SEEKING,
2443     0
2444   };
2445
2446   return types;
2447 }
2448
2449 /* handle queries for location and length in requested format */
2450 static gboolean
2451 gst_wavparse_pad_query (GstPad * pad, GstQuery * query)
2452 {
2453   gboolean res = TRUE;
2454   GstWavParse *wav = GST_WAVPARSE (gst_pad_get_parent (pad));
2455
2456   /* only if we know */
2457   if (wav->state != GST_WAVPARSE_DATA) {
2458     gst_object_unref (wav);
2459     return FALSE;
2460   }
2461
2462   GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
2463
2464   switch (GST_QUERY_TYPE (query)) {
2465     case GST_QUERY_POSITION:
2466     {
2467       gint64 curb;
2468       gint64 cur;
2469       GstFormat format;
2470
2471       /* this is not very precise, as we have pushed severla buffer upstream for prerolling */
2472       curb = wav->offset - wav->datastart;
2473       gst_query_parse_position (query, &format, NULL);
2474       GST_INFO_OBJECT (wav, "pos query at %" G_GINT64_FORMAT, curb);
2475
2476       switch (format) {
2477         case GST_FORMAT_TIME:
2478           res = gst_wavparse_pad_convert (pad, GST_FORMAT_BYTES, curb,
2479               &format, &cur);
2480           break;
2481         default:
2482           format = GST_FORMAT_BYTES;
2483           cur = curb;
2484           break;
2485       }
2486       if (res)
2487         gst_query_set_position (query, format, cur);
2488       break;
2489     }
2490     case GST_QUERY_DURATION:
2491     {
2492       gint64 duration = 0;
2493       GstFormat format;
2494
2495       gst_query_parse_duration (query, &format, NULL);
2496
2497       switch (format) {
2498         case GST_FORMAT_TIME:{
2499           if ((res = gst_wavparse_calculate_duration (wav))) {
2500             duration = wav->duration;
2501           }
2502           break;
2503         }
2504         default:
2505           format = GST_FORMAT_BYTES;
2506           duration = wav->datasize;
2507           break;
2508       }
2509       gst_query_set_duration (query, format, duration);
2510       break;
2511     }
2512     case GST_QUERY_CONVERT:
2513     {
2514       gint64 srcvalue, dstvalue;
2515       GstFormat srcformat, dstformat;
2516
2517       gst_query_parse_convert (query, &srcformat, &srcvalue,
2518           &dstformat, &dstvalue);
2519       res = gst_wavparse_pad_convert (pad, srcformat, srcvalue,
2520           &dstformat, &dstvalue);
2521       if (res)
2522         gst_query_set_convert (query, srcformat, srcvalue, dstformat, dstvalue);
2523       break;
2524     }
2525     case GST_QUERY_SEEKING:{
2526       GstFormat fmt;
2527       gboolean seekable = FALSE;
2528
2529       gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
2530       if (fmt == wav->segment.format) {
2531         if (wav->streaming) {
2532           GstQuery *q;
2533
2534           q = gst_query_new_seeking (GST_FORMAT_BYTES);
2535           if ((res = gst_pad_peer_query (wav->sinkpad, q))) {
2536             gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
2537             GST_LOG_OBJECT (wav, "upstream BYTE seekable %d", seekable);
2538           }
2539           gst_query_unref (q);
2540         } else {
2541           GST_LOG_OBJECT (wav, "looping => seekable");
2542           seekable = TRUE;
2543           res = TRUE;
2544         }
2545       } else if (fmt == GST_FORMAT_TIME) {
2546         res = TRUE;
2547       }
2548       if (res) {
2549         gst_query_set_seeking (query, fmt, seekable, 0, wav->segment.duration);
2550       }
2551       break;
2552     }
2553     default:
2554       res = gst_pad_query_default (pad, query);
2555       break;
2556   }
2557   gst_object_unref (wav);
2558   return res;
2559 }
2560
2561 static gboolean
2562 gst_wavparse_srcpad_event (GstPad * pad, GstEvent * event)
2563 {
2564   GstWavParse *wavparse = GST_WAVPARSE (gst_pad_get_parent (pad));
2565   gboolean res = FALSE;
2566
2567   GST_DEBUG_OBJECT (wavparse, "%s event", GST_EVENT_TYPE_NAME (event));
2568
2569   switch (GST_EVENT_TYPE (event)) {
2570     case GST_EVENT_SEEK:
2571       /* can only handle events when we are in the data state */
2572       if (wavparse->state == GST_WAVPARSE_DATA) {
2573         res = gst_wavparse_perform_seek (wavparse, event);
2574       }
2575       gst_event_unref (event);
2576       break;
2577     default:
2578       res = gst_pad_push_event (wavparse->sinkpad, event);
2579       break;
2580   }
2581   gst_object_unref (wavparse);
2582   return res;
2583 }
2584
2585 static gboolean
2586 gst_wavparse_sink_activate (GstPad * sinkpad)
2587 {
2588   GstWavParse *wav = GST_WAVPARSE (gst_pad_get_parent (sinkpad));
2589   gboolean res;
2590
2591   if (wav->adapter) {
2592     gst_adapter_clear (wav->adapter);
2593     g_object_unref (wav->adapter);
2594     wav->adapter = NULL;
2595   }
2596
2597   if (gst_pad_check_pull_range (sinkpad)) {
2598     GST_DEBUG ("going to pull mode");
2599     wav->streaming = FALSE;
2600     res = gst_pad_activate_pull (sinkpad, TRUE);
2601   } else {
2602     GST_DEBUG ("going to push (streaming) mode");
2603     wav->streaming = TRUE;
2604     wav->adapter = gst_adapter_new ();
2605     res = gst_pad_activate_push (sinkpad, TRUE);
2606   }
2607   gst_object_unref (wav);
2608   return res;
2609 }
2610
2611
2612 static gboolean
2613 gst_wavparse_sink_activate_pull (GstPad * sinkpad, gboolean active)
2614 {
2615   GstWavParse *wav = GST_WAVPARSE (GST_OBJECT_PARENT (sinkpad));
2616
2617   if (active) {
2618     /* if we have a scheduler we can start the task */
2619     wav->segment_running = TRUE;
2620     return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_wavparse_loop,
2621         sinkpad);
2622   } else {
2623     wav->segment_running = FALSE;
2624     return gst_pad_stop_task (sinkpad);
2625   }
2626 };
2627
2628 static GstStateChangeReturn
2629 gst_wavparse_change_state (GstElement * element, GstStateChange transition)
2630 {
2631   GstStateChangeReturn ret;
2632   GstWavParse *wav = GST_WAVPARSE (element);
2633
2634   switch (transition) {
2635     case GST_STATE_CHANGE_NULL_TO_READY:
2636       break;
2637     case GST_STATE_CHANGE_READY_TO_PAUSED:
2638       gst_wavparse_reset (wav);
2639       break;
2640     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
2641       break;
2642     default:
2643       break;
2644   }
2645
2646   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2647
2648   switch (transition) {
2649     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
2650       break;
2651     case GST_STATE_CHANGE_PAUSED_TO_READY:
2652       gst_wavparse_destroy_sourcepad (wav);
2653       gst_wavparse_reset (wav);
2654       break;
2655     case GST_STATE_CHANGE_READY_TO_NULL:
2656       break;
2657     default:
2658       break;
2659   }
2660   return ret;
2661 }
2662
2663 static gboolean
2664 plugin_init (GstPlugin * plugin)
2665 {
2666   gst_riff_init ();
2667
2668   return gst_element_register (plugin, "wavparse", GST_RANK_PRIMARY,
2669       GST_TYPE_WAVPARSE);
2670 }
2671
2672 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
2673     GST_VERSION_MINOR,
2674     "wavparse",
2675     "Parse a .wav file into raw audio",
2676     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)