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