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