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