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