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