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