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