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