gst_plugins_good/gst/wavparse/gstwavparse.c
changeset 2 5505e8908944
parent 0 0e761a78d257
child 7 567bb019e3e3
equal deleted inserted replaced
1:4c282e7dd6d3 2:5505e8908944
       
     1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
       
     2 /* GStreamer
       
     3  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
       
     4  * Copyright (C) <2006> Nokia Corporation, Stefan Kost <stefan.kost@nokia.com>.
       
     5  *
       
     6  * This library is free software; you can redistribute it and/or
       
     7  * modify it under the terms of the GNU Library General Public
       
     8  * License as published by the Free Software Foundation; either
       
     9  * version 2 of the License, or (at your option) any later version.
       
    10  *
       
    11  * This library is distributed in the hope that it will be useful,
       
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    14  * Library General Public License for more details.
       
    15  *
       
    16  * You should have received a copy of the GNU Library General Public
       
    17  * License along with this library; if not, write to the
       
    18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    19  * Boston, MA 02111-1307, USA.
       
    20  */
       
    21 
       
    22 /**
       
    23  * SECTION:element-wavparse
       
    24  *
       
    25  * <refsect2>
       
    26  * <para>
       
    27  * Parse a .wav file into raw or compressed audio.
       
    28  * </para>
       
    29  * <para>
       
    30  * This element currently only supports pull based scheduling.
       
    31  * </para>
       
    32  * <title>Example launch line</title>
       
    33  * <para>
       
    34  * <programlisting>
       
    35  * gst-launch filesrc location=sine.wav ! wavparse ! audioconvert ! alsasink
       
    36  * </programlisting>
       
    37  * Read a wav file and output to the soundcard using the ALSA element. The
       
    38  * wav file is assumed to contain raw uncompressed samples.
       
    39  * </para>
       
    40  * <para>
       
    41  * <programlisting>
       
    42  * gst-launch gnomevfssrc location=http://www.example.org/sine.wav ! queue ! wavparse ! audioconvert ! alsasink
       
    43  * </programlisting>
       
    44  * Stream data from
       
    45  * </para>
       
    46  * </refsect2>
       
    47  *
       
    48  * Last reviewed on 2006-03-03 (0.10.3)
       
    49  */
       
    50 
       
    51 #ifdef HAVE_CONFIG_H
       
    52 #include "config.h"
       
    53 #endif
       
    54 
       
    55 #include "string.h"
       
    56 #include "gstwavparse.h"
       
    57 #include <gst/riff/riff-ids.h>
       
    58 #include <gst/riff/riff-media.h>
       
    59 #include <gst/riff/riff-read.h>
       
    60 
       
    61 #ifndef __SYMBIAN32__
       
    62 #include <gst/gst-i18n-plugin.h>
       
    63 #else
       
    64 #include "gst/gst-i18n-plugin.h"
       
    65 #endif
       
    66 
       
    67 #ifdef __SYMBIAN32__
       
    68 #include <gst/gstinfo.h>
       
    69 #endif
       
    70 
       
    71 #ifndef G_MAXUINT32
       
    72 #define G_MAXUINT32 0xffffffff
       
    73 #endif
       
    74 
       
    75 GST_DEBUG_CATEGORY_STATIC (wavparse_debug);
       
    76 #define GST_CAT_DEFAULT (wavparse_debug)
       
    77 
       
    78 static void gst_wavparse_base_init (gpointer g_class);
       
    79 static void gst_wavparse_class_init (GstWavParseClass * klass);
       
    80 static void gst_wavparse_init (GstWavParse * wavparse);
       
    81 static void gst_wavparse_dispose (GObject * object);
       
    82 
       
    83 static gboolean gst_wavparse_sink_activate (GstPad * sinkpad);
       
    84 static gboolean gst_wavparse_sink_activate_pull (GstPad * sinkpad,
       
    85     gboolean active);
       
    86 static gboolean gst_wavparse_send_event (GstElement * element,
       
    87     GstEvent * event);
       
    88 static GstFlowReturn gst_wavparse_chain (GstPad * pad, GstBuffer * buf);
       
    89 static GstStateChangeReturn gst_wavparse_change_state (GstElement * element,
       
    90     GstStateChange transition);
       
    91 
       
    92 static gboolean gst_wavparse_pad_query (GstPad * pad, GstQuery * query);
       
    93 static const GstQueryType *gst_wavparse_get_query_types (GstPad * pad);
       
    94 static gboolean gst_wavparse_pad_convert (GstPad * pad,
       
    95     GstFormat src_format,
       
    96     gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
       
    97 
       
    98 static void gst_wavparse_loop (GstPad * pad);
       
    99 static gboolean gst_wavparse_srcpad_event (GstPad * pad, GstEvent * event);
       
   100 static void gst_wavparse_get_property (GObject * object, guint prop_id,
       
   101     GValue * value, GParamSpec * pspec);
       
   102 
       
   103 static const GstElementDetails gst_wavparse_details =
       
   104 GST_ELEMENT_DETAILS ("WAV audio demuxer",
       
   105     "Codec/Demuxer/Audio",
       
   106     "Parse a .wav file into raw audio",
       
   107     "Erik Walthinsen <omega@cse.ogi.edu>");
       
   108 
       
   109 static GstStaticPadTemplate sink_template_factory =
       
   110 //GST_STATIC_PAD_TEMPLATE ("wavparse_sink",
       
   111 GST_STATIC_PAD_TEMPLATE ("sink", 
       
   112     GST_PAD_SINK,
       
   113     GST_PAD_ALWAYS,
       
   114     GST_STATIC_CAPS ("audio/x-wav")
       
   115     );
       
   116 
       
   117 /* the pad is marked a sometimes and is added to the element when the
       
   118  * exact type is known. This makes it much easier for a static autoplugger
       
   119  * to connect the right decoder when needed.
       
   120  */
       
   121 static GstStaticPadTemplate src_template_factory =
       
   122  //   GST_STATIC_PAD_TEMPLATE ("wavparse_src",
       
   123     GST_STATIC_PAD_TEMPLATE ("src",
       
   124     GST_PAD_SRC,
       
   125     GST_PAD_SOMETIMES,
       
   126     GST_STATIC_CAPS ("audio/x-raw-int, "
       
   127         "endianness = (int) little_endian, "
       
   128         "signed = (boolean) { true, false }, "
       
   129         "width = (int) { 8, 16, 24, 32 }, "
       
   130         "depth = (int) { 8, 16, 24, 32 }, "
       
   131         "rate = (int) [ 8000, 96000 ], "
       
   132         "channels = (int) [ 1, 8 ]; "
       
   133         "audio/mpeg, "
       
   134         "mpegversion = (int) 1, "
       
   135         "layer = (int) [ 1, 3 ], "
       
   136         "rate = (int) [ 8000, 48000 ], "
       
   137         "channels = (int) [ 1, 2 ]; "
       
   138         "audio/x-alaw, "
       
   139         "rate = (int) [ 8000, 48000 ], "
       
   140         "channels = (int) [ 1, 2 ]; "
       
   141         "audio/x-mulaw, "
       
   142         "rate = (int) [ 8000, 48000 ], " "channels = (int) [ 1, 2 ];"
       
   143         "audio/x-adpcm, "
       
   144         "layout = (string) microsoft, "
       
   145         "block_align = (int) [ 1, 8192 ], "
       
   146         "rate = (int) [ 8000, 48000 ], "
       
   147         "channels = (int) [ 1, 2 ]; "
       
   148         "audio/x-adpcm, "
       
   149         "layout = (string) dvi, "
       
   150         "block_align = (int) [ 1, 8192 ], "
       
   151         "rate = (int) [ 8000, 48000 ], " "channels = (int) [ 1, 2 ];"
       
   152         "audio/x-vnd.sony.atrac3;"
       
   153         "audio/x-dts;" "audio/x-wma, " "wmaversion = (int) [ 1, 2 ]")
       
   154     );
       
   155 
       
   156 
       
   157 static GstElementClass *parent_class = NULL;
       
   158 
       
   159 GType
       
   160 gst_wavparse_get_type (void)
       
   161 {
       
   162   static GType wavparse_type = 0;
       
   163 
       
   164   if (!wavparse_type) {
       
   165     static const GTypeInfo wavparse_info = {
       
   166       sizeof (GstWavParseClass),
       
   167       gst_wavparse_base_init,
       
   168       NULL,
       
   169       (GClassInitFunc) gst_wavparse_class_init,
       
   170       NULL,
       
   171       NULL,
       
   172       sizeof (GstWavParse),
       
   173       0,
       
   174       (GInstanceInitFunc) gst_wavparse_init,
       
   175     };
       
   176 
       
   177     wavparse_type =
       
   178         g_type_register_static (GST_TYPE_ELEMENT, "GstWavParse",
       
   179         &wavparse_info, 0);
       
   180   }
       
   181   return wavparse_type;
       
   182 }
       
   183 
       
   184 
       
   185 static void
       
   186 gst_wavparse_base_init (gpointer g_class)
       
   187 {
       
   188   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
       
   189 
       
   190   /* register src pads */
       
   191   gst_element_class_add_pad_template (element_class,
       
   192       gst_static_pad_template_get (&sink_template_factory));
       
   193   gst_element_class_add_pad_template (element_class,
       
   194       gst_static_pad_template_get (&src_template_factory));
       
   195   gst_element_class_set_details (element_class, &gst_wavparse_details);
       
   196 }
       
   197 
       
   198 static void
       
   199 gst_wavparse_class_init (GstWavParseClass * klass)
       
   200 {
       
   201   GstElementClass *gstelement_class;
       
   202   GObjectClass *object_class;
       
   203 
       
   204   gstelement_class = (GstElementClass *) klass;
       
   205   object_class = (GObjectClass *) klass;
       
   206 
       
   207   parent_class = g_type_class_peek_parent (klass);
       
   208 
       
   209   object_class->get_property = gst_wavparse_get_property;
       
   210   object_class->dispose = gst_wavparse_dispose;
       
   211 
       
   212   gstelement_class->change_state = gst_wavparse_change_state;
       
   213   gstelement_class->send_event = gst_wavparse_send_event;
       
   214 }
       
   215 
       
   216 
       
   217 static void
       
   218 gst_wavparse_dispose (GObject * object)
       
   219 {
       
   220 	#ifndef __SYMBIAN32__
       
   221   GST_DEBUG("WAV: Dispose\n");
       
   222   #endif
       
   223   GstWavParse *wav = GST_WAVPARSE (object);
       
   224   #ifdef __SYMBIAN32__
       
   225   GST_DEBUG("WAV: Dispose\n");
       
   226 	#endif
       
   227 
       
   228   if (wav->adapter) {
       
   229     g_object_unref (wav->adapter);
       
   230     wav->adapter = NULL;
       
   231   }
       
   232 
       
   233   G_OBJECT_CLASS (parent_class)->dispose (object);
       
   234 }
       
   235 
       
   236 
       
   237 static void
       
   238 gst_wavparse_reset (GstWavParse * wavparse)
       
   239 {
       
   240   wavparse->state = GST_WAVPARSE_START;
       
   241 
       
   242   /* These will all be set correctly in the fmt chunk */
       
   243   wavparse->depth = 0;
       
   244   wavparse->rate = 0;
       
   245   wavparse->width = 0;
       
   246   wavparse->channels = 0;
       
   247   wavparse->blockalign = 0;
       
   248   wavparse->bps = 0;
       
   249   wavparse->offset = 0;
       
   250   wavparse->end_offset = 0;
       
   251   wavparse->dataleft = 0;
       
   252   wavparse->datasize = 0;
       
   253   wavparse->datastart = 0;
       
   254   wavparse->got_fmt = FALSE;
       
   255   wavparse->first = TRUE;
       
   256 
       
   257   if (wavparse->seek_event)
       
   258     gst_event_unref (wavparse->seek_event);
       
   259   wavparse->seek_event = NULL;
       
   260 
       
   261   /* we keep the segment info in time */
       
   262   gst_segment_init (&wavparse->segment, GST_FORMAT_TIME);
       
   263 }
       
   264 
       
   265 static void
       
   266 gst_wavparse_init (GstWavParse * wavparse)
       
   267 {
       
   268   gst_wavparse_reset (wavparse);
       
   269 
       
   270   /* sink */
       
   271   wavparse->sinkpad =
       
   272       gst_pad_new_from_static_template (&sink_template_factory, "sink");
       
   273   gst_pad_set_activate_function (wavparse->sinkpad,
       
   274       GST_DEBUG_FUNCPTR (gst_wavparse_sink_activate));
       
   275   gst_pad_set_activatepull_function (wavparse->sinkpad,
       
   276       GST_DEBUG_FUNCPTR (gst_wavparse_sink_activate_pull));
       
   277   gst_pad_set_chain_function (wavparse->sinkpad,
       
   278       GST_DEBUG_FUNCPTR (gst_wavparse_chain));
       
   279   gst_element_add_pad (GST_ELEMENT (wavparse), wavparse->sinkpad);
       
   280 
       
   281   /* src, will be created later */
       
   282   wavparse->srcpad = NULL;
       
   283 }
       
   284 
       
   285 static void
       
   286 gst_wavparse_destroy_sourcepad (GstWavParse * wavparse)
       
   287 {
       
   288   if (wavparse->srcpad) {
       
   289     gst_element_remove_pad (GST_ELEMENT (wavparse), wavparse->srcpad);
       
   290     wavparse->srcpad = NULL;
       
   291   }
       
   292 }
       
   293 
       
   294 static void
       
   295 gst_wavparse_create_sourcepad (GstWavParse * wavparse)
       
   296 {
       
   297   /* destroy previous one */
       
   298   gst_wavparse_destroy_sourcepad (wavparse);
       
   299 
       
   300   /* source */
       
   301   wavparse->srcpad =
       
   302       gst_pad_new_from_static_template (&src_template_factory, "src");
       
   303   gst_pad_use_fixed_caps (wavparse->srcpad);
       
   304   gst_pad_set_query_type_function (wavparse->srcpad,
       
   305       GST_DEBUG_FUNCPTR (gst_wavparse_get_query_types));
       
   306   gst_pad_set_query_function (wavparse->srcpad,
       
   307       GST_DEBUG_FUNCPTR (gst_wavparse_pad_query));
       
   308   gst_pad_set_event_function (wavparse->srcpad,
       
   309       GST_DEBUG_FUNCPTR (gst_wavparse_srcpad_event));
       
   310 
       
   311   GST_DEBUG_OBJECT (wavparse, "srcpad created");
       
   312 }
       
   313 
       
   314 static void
       
   315 gst_wavparse_get_property (GObject * object,
       
   316     guint prop_id, GValue * value, GParamSpec * pspec)
       
   317 {
       
   318   GstWavParse *wavparse;
       
   319 
       
   320   wavparse = GST_WAVPARSE (object);
       
   321 
       
   322   switch (prop_id) {
       
   323     default:
       
   324       break;
       
   325   }
       
   326 }
       
   327 
       
   328 
       
   329 
       
   330 #if 0
       
   331 static void
       
   332 gst_wavparse_parse_adtl (GstWavParse * wavparse, int len)
       
   333 {
       
   334   guint32 got_bytes;
       
   335   GstByteStream *bs = wavparse->bs;
       
   336   gst_riff_chunk *temp_chunk, chunk;
       
   337   guint8 *tempdata;
       
   338   struct _gst_riff_labl labl, *temp_labl;
       
   339   struct _gst_riff_ltxt ltxt, *temp_ltxt;
       
   340   struct _gst_riff_note note, *temp_note;
       
   341   char *label_name;
       
   342   GstProps *props;
       
   343   GstPropsEntry *entry;
       
   344   GstCaps *new_caps;
       
   345   GList *caps = NULL;
       
   346 
       
   347   props = wavparse->metadata->properties;
       
   348 
       
   349   while (len > 0) {
       
   350     got_bytes =
       
   351         gst_bytestream_peek_bytes (bs, &tempdata, sizeof (gst_riff_chunk));
       
   352     if (got_bytes != sizeof (gst_riff_chunk)) {
       
   353       return;
       
   354     }
       
   355     temp_chunk = (gst_riff_chunk *) tempdata;
       
   356 
       
   357     chunk.id = GUINT32_FROM_LE (temp_chunk->id);
       
   358     chunk.size = GUINT32_FROM_LE (temp_chunk->size);
       
   359 
       
   360     if (chunk.size == 0) {
       
   361       gst_bytestream_flush (bs, sizeof (gst_riff_chunk));
       
   362       len -= sizeof (gst_riff_chunk);
       
   363       continue;
       
   364     }
       
   365 
       
   366     switch (chunk.id) {
       
   367       case GST_RIFF_adtl_labl:
       
   368         got_bytes =
       
   369             gst_bytestream_peek_bytes (bs, &tempdata,
       
   370             sizeof (struct _gst_riff_labl));
       
   371         if (got_bytes != sizeof (struct _gst_riff_labl)) {
       
   372           return;
       
   373         }
       
   374 
       
   375         temp_labl = (struct _gst_riff_labl *) tempdata;
       
   376         labl.id = GUINT32_FROM_LE (temp_labl->id);
       
   377         labl.size = GUINT32_FROM_LE (temp_labl->size);
       
   378         labl.identifier = GUINT32_FROM_LE (temp_labl->identifier);
       
   379 
       
   380         gst_bytestream_flush (bs, sizeof (struct _gst_riff_labl));
       
   381         len -= sizeof (struct _gst_riff_labl);
       
   382 
       
   383         got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, labl.size - 4);
       
   384         if (got_bytes != labl.size - 4) {
       
   385           return;
       
   386         }
       
   387 
       
   388         label_name = (char *) tempdata;
       
   389 
       
   390         gst_bytestream_flush (bs, ((labl.size - 4) + 1) & ~1);
       
   391         len -= (((labl.size - 4) + 1) & ~1);
       
   392 
       
   393         new_caps = gst_caps_new ("label",
       
   394             "application/x-gst-metadata",
       
   395             gst_props_new ("identifier", G_TYPE_INT (labl.identifier),
       
   396                 "name", G_TYPE_STRING (label_name), NULL));
       
   397 
       
   398         if (gst_props_get (props, "labels", &caps, NULL)) {
       
   399           caps = g_list_append (caps, new_caps);
       
   400         } else {
       
   401           caps = g_list_append (NULL, new_caps);
       
   402 
       
   403           entry = gst_props_entry_new ("labels", GST_PROPS_GLIST (caps));
       
   404           gst_props_add_entry (props, entry);
       
   405         }
       
   406 
       
   407         break;
       
   408 
       
   409       case GST_RIFF_adtl_ltxt:
       
   410         got_bytes =
       
   411             gst_bytestream_peek_bytes (bs, &tempdata,
       
   412             sizeof (struct _gst_riff_ltxt));
       
   413         if (got_bytes != sizeof (struct _gst_riff_ltxt)) {
       
   414           return;
       
   415         }
       
   416 
       
   417         temp_ltxt = (struct _gst_riff_ltxt *) tempdata;
       
   418         ltxt.id = GUINT32_FROM_LE (temp_ltxt->id);
       
   419         ltxt.size = GUINT32_FROM_LE (temp_ltxt->size);
       
   420         ltxt.identifier = GUINT32_FROM_LE (temp_ltxt->identifier);
       
   421         ltxt.length = GUINT32_FROM_LE (temp_ltxt->length);
       
   422         ltxt.purpose = GUINT32_FROM_LE (temp_ltxt->purpose);
       
   423         ltxt.country = GUINT16_FROM_LE (temp_ltxt->country);
       
   424         ltxt.language = GUINT16_FROM_LE (temp_ltxt->language);
       
   425         ltxt.dialect = GUINT16_FROM_LE (temp_ltxt->dialect);
       
   426         ltxt.codepage = GUINT16_FROM_LE (temp_ltxt->codepage);
       
   427 
       
   428         gst_bytestream_flush (bs, sizeof (struct _gst_riff_ltxt));
       
   429         len -= sizeof (struct _gst_riff_ltxt);
       
   430 
       
   431         if (ltxt.size - 20 > 0) {
       
   432           got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, ltxt.size - 20);
       
   433           if (got_bytes != ltxt.size - 20) {
       
   434             return;
       
   435           }
       
   436 
       
   437           gst_bytestream_flush (bs, ((ltxt.size - 20) + 1) & ~1);
       
   438           len -= (((ltxt.size - 20) + 1) & ~1);
       
   439 
       
   440           label_name = (char *) tempdata;
       
   441         } else {
       
   442           label_name = "";
       
   443         }
       
   444 
       
   445         new_caps = gst_caps_new ("ltxt",
       
   446             "application/x-gst-metadata",
       
   447             gst_props_new ("identifier", G_TYPE_INT (ltxt.identifier),
       
   448                 "name", G_TYPE_STRING (label_name),
       
   449                 "length", G_TYPE_INT (ltxt.length), NULL));
       
   450 
       
   451         if (gst_props_get (props, "ltxts", &caps, NULL)) {
       
   452           caps = g_list_append (caps, new_caps);
       
   453         } else {
       
   454           caps = g_list_append (NULL, new_caps);
       
   455 
       
   456           entry = gst_props_entry_new ("ltxts", GST_PROPS_GLIST (caps));
       
   457           gst_props_add_entry (props, entry);
       
   458         }
       
   459 
       
   460         break;
       
   461 
       
   462       case GST_RIFF_adtl_note:
       
   463         got_bytes =
       
   464             gst_bytestream_peek_bytes (bs, &tempdata,
       
   465             sizeof (struct _gst_riff_note));
       
   466         if (got_bytes != sizeof (struct _gst_riff_note)) {
       
   467           return;
       
   468         }
       
   469 
       
   470         temp_note = (struct _gst_riff_note *) tempdata;
       
   471         note.id = GUINT32_FROM_LE (temp_note->id);
       
   472         note.size = GUINT32_FROM_LE (temp_note->size);
       
   473         note.identifier = GUINT32_FROM_LE (temp_note->identifier);
       
   474 
       
   475         gst_bytestream_flush (bs, sizeof (struct _gst_riff_note));
       
   476         len -= sizeof (struct _gst_riff_note);
       
   477 
       
   478         got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, note.size - 4);
       
   479         if (got_bytes != note.size - 4) {
       
   480           return;
       
   481         }
       
   482 
       
   483         gst_bytestream_flush (bs, ((note.size - 4) + 1) & ~1);
       
   484         len -= (((note.size - 4) + 1) & ~1);
       
   485 
       
   486         label_name = (char *) tempdata;
       
   487 
       
   488         new_caps = gst_caps_new ("note",
       
   489             "application/x-gst-metadata",
       
   490             gst_props_new ("identifier", G_TYPE_INT (note.identifier),
       
   491                 "name", G_TYPE_STRING (label_name), NULL));
       
   492 
       
   493         if (gst_props_get (props, "notes", &caps, NULL)) {
       
   494           caps = g_list_append (caps, new_caps);
       
   495         } else {
       
   496           caps = g_list_append (NULL, new_caps);
       
   497 
       
   498           entry = gst_props_entry_new ("notes", GST_PROPS_GLIST (caps));
       
   499           gst_props_add_entry (props, entry);
       
   500         }
       
   501 
       
   502         break;
       
   503 
       
   504       default:
       
   505         g_print ("Unknown chunk: %" GST_FOURCC_FORMAT "\n",
       
   506             GST_FOURCC_ARGS (chunk.id));
       
   507         return;
       
   508     }
       
   509   }
       
   510 
       
   511   g_object_notify (G_OBJECT (wavparse), "metadata");
       
   512 }
       
   513 
       
   514 static void
       
   515 gst_wavparse_parse_cues (GstWavParse * wavparse, int len)
       
   516 {
       
   517   guint32 got_bytes;
       
   518   GstByteStream *bs = wavparse->bs;
       
   519   struct _gst_riff_cue *temp_cue, cue;
       
   520   struct _gst_riff_cuepoints *points;
       
   521   guint8 *tempdata;
       
   522   int i;
       
   523   GList *cues = NULL;
       
   524   GstPropsEntry *entry;
       
   525 
       
   526   while (len > 0) {
       
   527     int required;
       
   528 
       
   529     got_bytes =
       
   530         gst_bytestream_peek_bytes (bs, &tempdata,
       
   531         sizeof (struct _gst_riff_cue));
       
   532     temp_cue = (struct _gst_riff_cue *) tempdata;
       
   533 
       
   534     /* fixup for our big endian friends */
       
   535     cue.id = GUINT32_FROM_LE (temp_cue->id);
       
   536     cue.size = GUINT32_FROM_LE (temp_cue->size);
       
   537     cue.cuepoints = GUINT32_FROM_LE (temp_cue->cuepoints);
       
   538 
       
   539     gst_bytestream_flush (bs, sizeof (struct _gst_riff_cue));
       
   540     if (got_bytes != sizeof (struct _gst_riff_cue)) {
       
   541       return;
       
   542     }
       
   543 
       
   544     len -= sizeof (struct _gst_riff_cue);
       
   545 
       
   546     /* -4 because cue.size contains the cuepoints size
       
   547        and we've already flushed that out of the system */
       
   548     required = cue.size - 4;
       
   549     got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, required);
       
   550     gst_bytestream_flush (bs, ((required) + 1) & ~1);
       
   551     if (got_bytes != required) {
       
   552       return;
       
   553     }
       
   554 
       
   555     len -= (((cue.size - 4) + 1) & ~1);
       
   556 
       
   557     /* now we have an array of struct _gst_riff_cuepoints in tempdata */
       
   558     points = (struct _gst_riff_cuepoints *) tempdata;
       
   559 
       
   560     for (i = 0; i < cue.cuepoints; i++) {
       
   561       GstCaps *caps;
       
   562 
       
   563       caps = gst_caps_new ("cues",
       
   564           "application/x-gst-metadata",
       
   565           gst_props_new ("identifier", G_TYPE_INT (points[i].identifier),
       
   566               "position", G_TYPE_INT (points[i].offset), NULL));
       
   567       cues = g_list_append (cues, caps);
       
   568     }
       
   569 
       
   570     entry = gst_props_entry_new ("cues", GST_PROPS_GLIST (cues));
       
   571     gst_props_add_entry (wavparse->metadata->properties, entry);
       
   572   }
       
   573 
       
   574   g_object_notify (G_OBJECT (wavparse), "metadata");
       
   575 }
       
   576 
       
   577 /* Read 'fmt ' header */
       
   578 static gboolean
       
   579 gst_wavparse_fmt (GstWavParse * wav)
       
   580 {
       
   581   gst_riff_strf_auds *header = NULL;
       
   582   GstCaps *caps;
       
   583 
       
   584   if (!gst_riff_read_strf_auds (wav, &header)) {
       
   585     g_warning ("Not fmt");
       
   586     return FALSE;
       
   587   }
       
   588 
       
   589   wav->format = header->format;
       
   590   wav->rate = header->rate;
       
   591   wav->channels = header->channels;
       
   592   if (wav->channels == 0) {
       
   593     GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL),
       
   594         ("Stream claims to contain zero channels - invalid data"));
       
   595     g_free (header);
       
   596     return FALSE;
       
   597   }
       
   598   wav->blockalign = header->blockalign;
       
   599   wav->width = (header->blockalign * 8) / header->channels;
       
   600   wav->depth = header->size;
       
   601   wav->bps = header->av_bps;
       
   602   if (wav->bps <= 0) {
       
   603     GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL),
       
   604         ("Stream claims to bitrate of <= zero - invalid data"));
       
   605     g_free (header);
       
   606     return FALSE;
       
   607   }
       
   608 
       
   609   /* Note: gst_riff_create_audio_caps might nedd to fix values in
       
   610    * the header header depending on the format, so call it first */
       
   611   caps = gst_riff_create_audio_caps (header->format, NULL, header, NULL);
       
   612 
       
   613   g_free (header);
       
   614 
       
   615   if (caps) {
       
   616     gst_wavparse_create_sourcepad (wav);
       
   617     gst_pad_use_fixed_caps (wav->srcpad);
       
   618     gst_pad_set_active (wav->srcpad, TRUE);
       
   619     gst_pad_set_caps (wav->srcpad, caps);
       
   620     gst_caps_free (caps);
       
   621     gst_element_add_pad (GST_ELEMENT (wav), wav->srcpad);
       
   622     gst_element_no_more_pads (GST_ELEMENT (wav));
       
   623     GST_DEBUG ("frequency %d, channels %d", wav->rate, wav->channels);
       
   624   } else {
       
   625     GST_ELEMENT_ERROR (wav, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
       
   626     return FALSE;
       
   627   }
       
   628 
       
   629   return TRUE;
       
   630 }
       
   631 
       
   632 static gboolean
       
   633 gst_wavparse_other (GstWavParse * wav)
       
   634 {
       
   635   guint32 tag, length;
       
   636 
       
   637   if (!gst_riff_peek_head (wav, &tag, &length, NULL)) {
       
   638     GST_WARNING_OBJECT (wav, "could not peek head");
       
   639     return FALSE;
       
   640   }
       
   641   GST_DEBUG_OBJECT (wav, "got tag (%08x) %4.4s, length %d", tag,
       
   642       (gchar *) & tag, length);
       
   643 
       
   644   switch (tag) {
       
   645     case GST_RIFF_TAG_LIST:
       
   646       if (!(tag = gst_riff_peek_list (wav))) {
       
   647         GST_WARNING_OBJECT (wav, "could not peek list");
       
   648         return FALSE;
       
   649       }
       
   650 
       
   651       switch (tag) {
       
   652         case GST_RIFF_LIST_INFO:
       
   653           if (!gst_riff_read_list (wav, &tag) || !gst_riff_read_info (wav)) {
       
   654             GST_WARNING_OBJECT (wav, "could not read list");
       
   655             return FALSE;
       
   656           }
       
   657           break;
       
   658 
       
   659         case GST_RIFF_LIST_adtl:
       
   660           if (!gst_riff_read_skip (wav)) {
       
   661             GST_WARNING_OBJECT (wav, "could not read skip");
       
   662             return FALSE;
       
   663           }
       
   664           break;
       
   665 
       
   666         default:
       
   667           GST_DEBUG_OBJECT (wav, "skipping tag (%08x) %4.4s", tag,
       
   668               (gchar *) & tag);
       
   669           if (!gst_riff_read_skip (wav)) {
       
   670             GST_WARNING_OBJECT (wav, "could not read skip");
       
   671             return FALSE;
       
   672           }
       
   673           break;
       
   674       }
       
   675 
       
   676       break;
       
   677 
       
   678     case GST_RIFF_TAG_data:
       
   679       if (!gst_bytestream_flush (wav->bs, 8)) {
       
   680         GST_WARNING_OBJECT (wav, "could not flush 8 bytes");
       
   681         return FALSE;
       
   682       }
       
   683 
       
   684       GST_DEBUG_OBJECT (wav, "switching to data mode");
       
   685       wav->state = GST_WAVPARSE_DATA;
       
   686       wav->datastart = gst_bytestream_tell (wav->bs);
       
   687       if (length == 0) {
       
   688         guint64 file_length;
       
   689 
       
   690         /* length is 0, data probably stretches to the end
       
   691          * of file */
       
   692         GST_DEBUG_OBJECT (wav, "length is 0 trying to find length");
       
   693         /* get length of file */
       
   694         file_length = gst_bytestream_length (wav->bs);
       
   695         if (file_length == -1) {
       
   696           GST_DEBUG_OBJECT (wav,
       
   697               "could not get file length, assuming data to eof");
       
   698           /* could not get length, assuming till eof */
       
   699           length = G_MAXUINT32;
       
   700         }
       
   701         if (file_length > G_MAXUINT32) {
       
   702           GST_DEBUG_OBJECT (wav, "file length %lld, clipping to 32 bits");
       
   703           /* could not get length, assuming till eof */
       
   704           length = G_MAXUINT32;
       
   705         } else {
       
   706           GST_DEBUG_OBJECT (wav, "file length %lld, datalength",
       
   707               file_length, length);
       
   708           /* substract offset of datastart from length */
       
   709           length = file_length - wav->datastart;
       
   710           GST_DEBUG_OBJECT (wav, "datalength %lld", length);
       
   711         }
       
   712       }
       
   713       wav->datasize = (guint64) length;
       
   714       break;
       
   715 
       
   716     case GST_RIFF_TAG_cue:
       
   717       if (!gst_riff_read_skip (wav)) {
       
   718         GST_WARNING_OBJECT (wav, "could not read skip");
       
   719         return FALSE;
       
   720       }
       
   721       break;
       
   722 
       
   723     default:
       
   724       GST_DEBUG_OBJECT (wav, "skipping tag (%08x) %4.4s", tag, (gchar *) & tag);
       
   725       if (!gst_riff_read_skip (wav))
       
   726         return FALSE;
       
   727       break;
       
   728   }
       
   729 
       
   730   return TRUE;
       
   731 }
       
   732 #endif
       
   733 
       
   734 
       
   735 
       
   736 static gboolean
       
   737 gst_wavparse_parse_file_header (GstElement * element, GstBuffer * buf)
       
   738 {
       
   739   guint32 doctype;
       
   740   
       
   741   if (!gst_riff_parse_file_header (element, buf, &doctype))
       
   742    return FALSE;
       
   743 
       
   744   if (doctype != GST_RIFF_RIFF_WAVE)
       
   745     goto not_wav;
       
   746 
       
   747   return TRUE;
       
   748 
       
   749   /* ERRORS */
       
   750 not_wav:
       
   751 
       
   752   {
       
   753     GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL),
       
   754         ("File is not an WAVE file: %" GST_FOURCC_FORMAT,
       
   755             GST_FOURCC_ARGS (doctype)));
       
   756     return FALSE;
       
   757   }
       
   758 }
       
   759 
       
   760 static GstFlowReturn
       
   761 gst_wavparse_stream_init (GstWavParse * wav)
       
   762 {
       
   763   GstFlowReturn res;
       
   764   GstBuffer *buf = NULL;
       
   765 
       
   766   
       
   767   if ((res = gst_pad_pull_range (wav->sinkpad,
       
   768               wav->offset, 12, &buf)) != GST_FLOW_OK)
       
   769       {
       
   770  
       
   771     return res;
       
   772       }
       
   773   else if (!gst_wavparse_parse_file_header (GST_ELEMENT (wav), buf))
       
   774     return GST_FLOW_ERROR;
       
   775 
       
   776   wav->offset += 12;
       
   777 
       
   778   return GST_FLOW_OK;
       
   779 }
       
   780 
       
   781 /* This function is used to perform seeks on the element in 
       
   782  * pull mode.
       
   783  *
       
   784  * It also works when event is NULL, in which case it will just
       
   785  * start from the last configured segment. This technique is
       
   786  * used when activating the element and to perform the seek in
       
   787  * READY.
       
   788  */
       
   789 static gboolean
       
   790 gst_wavparse_perform_seek (GstWavParse * wav, GstEvent * event)
       
   791 {
       
   792   gboolean res;
       
   793   gdouble rate;
       
   794   GstEvent *newsegment;
       
   795   GstFormat format;
       
   796   GstSeekFlags flags;
       
   797   GstSeekType cur_type, stop_type;
       
   798   gint64 cur, stop;
       
   799   gboolean flush;
       
   800   gboolean update;
       
   801   GstSegment seeksegment;
       
   802 
       
   803   if (event) {
       
   804     GST_DEBUG_OBJECT (wav, "doing seek with event");
       
   805 
       
   806     gst_event_parse_seek (event, &rate, &format, &flags,
       
   807         &cur_type, &cur, &stop_type, &stop);
       
   808 
       
   809     /* we have to have a format as the segment format. Try to convert
       
   810      * if not. */
       
   811     if (format != GST_FORMAT_TIME) {
       
   812       GstFormat fmt;
       
   813 
       
   814       fmt = GST_FORMAT_TIME;
       
   815       res = TRUE;
       
   816       if (cur_type != GST_SEEK_TYPE_NONE)
       
   817         res = gst_pad_query_convert (wav->srcpad, format, cur, &fmt, &cur);
       
   818       if (res && stop_type != GST_SEEK_TYPE_NONE)
       
   819         res = gst_pad_query_convert (wav->srcpad, format, stop, &fmt, &stop);
       
   820       if (!res)
       
   821         goto no_format;
       
   822 
       
   823       format = fmt;
       
   824     }
       
   825   } else {
       
   826     GST_DEBUG_OBJECT (wav, "doing seek without event");
       
   827     flags = 0;
       
   828   }
       
   829 
       
   830   flush = flags & GST_SEEK_FLAG_FLUSH;
       
   831 
       
   832   if (flush && wav->srcpad) {
       
   833     GST_DEBUG_OBJECT (wav, "sending flush start");
       
   834     gst_pad_push_event (wav->srcpad, gst_event_new_flush_start ());
       
   835   } else {
       
   836     gst_pad_pause_task (wav->sinkpad);
       
   837   }
       
   838 
       
   839   GST_PAD_STREAM_LOCK (wav->sinkpad);
       
   840 
       
   841   /* copy segment, we need this because we still need the old
       
   842    * segment when we close the current segment. */
       
   843   memcpy (&seeksegment, &wav->segment, sizeof (GstSegment));
       
   844 
       
   845   if (event) {
       
   846     GST_DEBUG_OBJECT (wav, "configuring seek");
       
   847     gst_segment_set_seek (&seeksegment, rate, format, flags,
       
   848         cur_type, cur, stop_type, stop, &update);
       
   849   }
       
   850 
       
   851   if ((stop = seeksegment.stop) == -1)
       
   852     stop = seeksegment.duration;
       
   853 
       
   854   if (cur_type != GST_SEEK_TYPE_NONE) {
       
   855     wav->offset =
       
   856         gst_util_uint64_scale_int (seeksegment.last_stop, wav->bps, GST_SECOND);
       
   857     wav->offset -= wav->offset % wav->bytes_per_sample;
       
   858     wav->offset += wav->datastart;
       
   859   }
       
   860 
       
   861   if (stop != -1) {
       
   862     wav->end_offset = gst_util_uint64_scale_int (stop, wav->bps, GST_SECOND);
       
   863     wav->end_offset +=
       
   864         wav->bytes_per_sample - (wav->end_offset % wav->bytes_per_sample);
       
   865     wav->end_offset += wav->datastart;
       
   866   } else {
       
   867     wav->end_offset = wav->datasize + wav->datastart;
       
   868   }
       
   869   wav->offset = MIN (wav->offset, wav->end_offset);
       
   870   wav->dataleft = wav->end_offset - wav->offset;
       
   871 
       
   872   GST_DEBUG_OBJECT (wav,
       
   873       "seek: offset %" G_GUINT64_FORMAT ", end %" G_GUINT64_FORMAT ", segment %"
       
   874       GST_TIME_FORMAT " -- %" GST_TIME_FORMAT, wav->offset, wav->end_offset,
       
   875       GST_TIME_ARGS (seeksegment.start), GST_TIME_ARGS (stop));
       
   876 
       
   877   /* prepare for streaming again */
       
   878   if (wav->srcpad) {
       
   879     if (flush) {
       
   880       GST_DEBUG_OBJECT (wav, "sending flush stop");
       
   881       gst_pad_push_event (wav->srcpad, gst_event_new_flush_stop ());
       
   882     } else if (wav->segment_running) {
       
   883       /* we are running the current segment and doing a non-flushing seek,
       
   884        * close the segment first based on the last_stop. */
       
   885       GST_DEBUG_OBJECT (wav, "closing running segment %" G_GINT64_FORMAT
       
   886           " to %" G_GINT64_FORMAT, wav->segment.start, wav->segment.last_stop);
       
   887 
       
   888       gst_pad_push_event (wav->srcpad,
       
   889           gst_event_new_new_segment (TRUE,
       
   890               wav->segment.rate, wav->segment.format,
       
   891               wav->segment.start, wav->segment.last_stop, wav->segment.time));
       
   892     }
       
   893   }
       
   894 
       
   895   memcpy (&wav->segment, &seeksegment, sizeof (GstSegment));
       
   896 
       
   897   if (wav->segment.flags & GST_SEEK_FLAG_SEGMENT) {
       
   898     gst_element_post_message (GST_ELEMENT (wav),
       
   899         gst_message_new_segment_start (GST_OBJECT (wav),
       
   900             wav->segment.format, wav->segment.last_stop));
       
   901   }
       
   902 
       
   903   /* now send the newsegment */
       
   904   GST_DEBUG_OBJECT (wav, "Sending newsegment from %" G_GINT64_FORMAT
       
   905       " to %" G_GINT64_FORMAT, wav->segment.start, stop);
       
   906 
       
   907   newsegment =
       
   908       gst_event_new_new_segment (FALSE, wav->segment.rate,
       
   909       wav->segment.format, wav->segment.last_stop, stop, wav->segment.time);
       
   910 
       
   911   if (wav->srcpad) {
       
   912     gst_pad_push_event (wav->srcpad, newsegment);
       
   913   } else {
       
   914     /* send later when we actually create the source pad */
       
   915     g_assert (wav->newsegment == NULL);
       
   916     wav->newsegment = newsegment;
       
   917   }
       
   918 
       
   919   wav->segment_running = TRUE;
       
   920   if (!wav->streaming) {
       
   921     gst_pad_start_task (wav->sinkpad, (GstTaskFunction) gst_wavparse_loop,
       
   922         wav->sinkpad);
       
   923   }
       
   924 
       
   925   GST_PAD_STREAM_UNLOCK (wav->sinkpad);
       
   926 
       
   927   return TRUE;
       
   928 
       
   929   /* ERRORS */
       
   930 no_format:
       
   931   {
       
   932     GST_DEBUG_OBJECT (wav, "unsupported format given, seek aborted.");
       
   933     return FALSE;
       
   934   }
       
   935 }
       
   936 
       
   937 /*
       
   938  * gst_wavparse_peek_chunk_info:
       
   939  * @wav Wavparse object
       
   940  * @tag holder for tag
       
   941  * @size holder for tag size
       
   942  *                         
       
   943  * Peek next chunk info (tag and size)                         
       
   944  *
       
   945  * Returns: %TRUE when one chunk info has been got from the adapter
       
   946  */
       
   947 static gboolean
       
   948 gst_wavparse_peek_chunk_info (GstWavParse * wav, guint32 * tag, guint32 * size)
       
   949 {
       
   950   const guint8 *data = NULL;
       
   951 
       
   952   if (gst_adapter_available (wav->adapter) < 8) {
       
   953     return FALSE;
       
   954   }
       
   955 
       
   956   GST_DEBUG ("Next chunk size is %d bytes", *size);
       
   957   data = gst_adapter_peek (wav->adapter, 8);
       
   958   *tag = GST_READ_UINT32_LE (data);
       
   959   *size = GST_READ_UINT32_LE (data + 4);
       
   960 
       
   961   return TRUE;
       
   962 }
       
   963 
       
   964 /*
       
   965  * gst_wavparse_peek_chunk:
       
   966  * @wav Wavparse object
       
   967  * @tag holder for tag
       
   968  * @size holder for tag size
       
   969  *
       
   970  * Peek enough data for one full chunk
       
   971  *
       
   972  * Returns: %TRUE when one chunk has been got
       
   973  */
       
   974 static gboolean
       
   975 gst_wavparse_peek_chunk (GstWavParse * wav, guint32 * tag, guint32 * size)
       
   976 {
       
   977   guint32 peek_size = 0;
       
   978 
       
   979   gst_wavparse_peek_chunk_info (wav, tag, size);
       
   980   GST_DEBUG ("Need to peek chunk of %d bytes", *size);
       
   981   peek_size = (*size + 1) & ~1;
       
   982 
       
   983   if (gst_adapter_available (wav->adapter) >= (8 + peek_size)) {
       
   984     return TRUE;
       
   985   } else {
       
   986     return FALSE;
       
   987   }
       
   988 }
       
   989 
       
   990 static gboolean
       
   991 gst_wavparse_get_upstream_size (GstWavParse * wav, gint64 * len)
       
   992 {
       
   993   gboolean res = FALSE;
       
   994   GstFormat fmt = GST_FORMAT_BYTES;
       
   995   GstPad *peer;
       
   996 
       
   997   if ((peer = gst_pad_get_peer (wav->sinkpad))) {
       
   998     res = gst_pad_query_duration (peer, &fmt, len);
       
   999     gst_object_unref (peer);
       
  1000   }
       
  1001 
       
  1002   return res;
       
  1003 }
       
  1004 
       
  1005 static GstFlowReturn
       
  1006 gst_wavparse_stream_headers (GstWavParse * wav)
       
  1007 {
       
  1008   GstFlowReturn res;
       
  1009   GstBuffer *buf;
       
  1010   gst_riff_strf_auds *header = NULL;
       
  1011   guint32 tag, size;
       
  1012   gboolean gotdata = FALSE;
       
  1013   GstCaps *caps;
       
  1014   gint64 duration;
       
  1015   gchar *codec_name = NULL;
       
  1016   GstEvent **event_p;
       
  1017 
       
  1018   
       
  1019   if (!wav->got_fmt) {
       
  1020     GstBuffer *extra;
       
  1021 
       
  1022     /* The header start with a 'fmt ' tag */
       
  1023 
       
  1024     if (wav->streaming) {
       
  1025       if (!gst_wavparse_peek_chunk (wav, &tag, &size))
       
  1026         return GST_FLOW_OK;
       
  1027 
       
  1028       buf = gst_buffer_new ();
       
  1029       gst_buffer_ref (buf);
       
  1030       gst_adapter_flush (wav->adapter, 8);
       
  1031       wav->offset += 8;
       
  1032       GST_BUFFER_DATA (buf) = (guint8 *) gst_adapter_peek (wav->adapter, size);
       
  1033       GST_BUFFER_SIZE (buf) = size;
       
  1034 
       
  1035     } else {
       
  1036       if ((res = gst_riff_read_chunk (GST_ELEMENT (wav), wav->sinkpad,
       
  1037                   &wav->offset, &tag, &buf)) != GST_FLOW_OK)
       
  1038         return res;
       
  1039     }
       
  1040 
       
  1041     if (tag != GST_RIFF_TAG_fmt)
       
  1042       goto invalid_wav;
       
  1043 
       
  1044     if (!(gst_riff_parse_strf_auds (GST_ELEMENT (wav), buf, &header, &extra)))
       
  1045       goto parse_header_error;
       
  1046 
       
  1047     if (wav->streaming) {
       
  1048       gst_adapter_flush (wav->adapter, size);
       
  1049       wav->offset += size;
       
  1050       GST_BUFFER_DATA (buf) = NULL;
       
  1051       gst_buffer_unref (buf);
       
  1052     }
       
  1053 
       
  1054     /* Note: gst_riff_create_audio_caps might nedd to fix values in
       
  1055      * the header header depending on the format, so call it first */
       
  1056     caps =
       
  1057         gst_riff_create_audio_caps (header->format, NULL, header, extra,
       
  1058         NULL, &codec_name);
       
  1059 
       
  1060     if (extra)
       
  1061       gst_buffer_unref (extra);
       
  1062 
       
  1063     wav->format = header->format;
       
  1064     wav->rate = header->rate;
       
  1065     wav->channels = header->channels;
       
  1066 
       
  1067     if (wav->channels == 0)
       
  1068       goto no_channels;
       
  1069 
       
  1070     wav->blockalign = header->blockalign;
       
  1071     wav->width = (header->blockalign * 8) / header->channels;
       
  1072     wav->depth = header->size;
       
  1073     wav->bps = header->av_bps;
       
  1074 
       
  1075     if (wav->bps <= 0)
       
  1076       goto no_bitrate;
       
  1077 
       
  1078     wav->bytes_per_sample = wav->channels * wav->width / 8;
       
  1079     if (wav->bytes_per_sample <= 0)
       
  1080       goto no_bytes_per_sample;
       
  1081 
       
  1082     g_free (header);
       
  1083 
       
  1084     if (!caps)
       
  1085       goto unknown_format;
       
  1086 
       
  1087     GST_DEBUG_OBJECT (wav, "blockalign = %u", (guint) wav->blockalign);
       
  1088     GST_DEBUG_OBJECT (wav, "width      = %u", (guint) wav->width);
       
  1089     GST_DEBUG_OBJECT (wav, "depth      = %u", (guint) wav->depth);
       
  1090     GST_DEBUG_OBJECT (wav, "bps        = %u", (guint) wav->bps);
       
  1091 
       
  1092     /* create pad later so we can sniff the first few bytes
       
  1093      * of the real data and correct our caps if necessary */
       
  1094     gst_caps_replace (&wav->caps, caps);
       
  1095     gst_caps_replace (&caps, NULL);
       
  1096 
       
  1097     wav->got_fmt = TRUE;
       
  1098 
       
  1099     if (codec_name) {
       
  1100       wav->tags = gst_tag_list_new ();
       
  1101 
       
  1102       gst_tag_list_add (wav->tags, GST_TAG_MERGE_REPLACE,
       
  1103           GST_TAG_AUDIO_CODEC, codec_name, NULL);
       
  1104 
       
  1105       g_free (codec_name);
       
  1106       codec_name = NULL;
       
  1107     }
       
  1108 
       
  1109     GST_DEBUG_OBJECT (wav, "frequency %d, channels %d", wav->rate,
       
  1110         wav->channels);
       
  1111   }
       
  1112 
       
  1113   /* loop headers until we get data */
       
  1114   while (!gotdata) {
       
  1115     if (wav->streaming) {
       
  1116       if (!gst_wavparse_peek_chunk_info (wav, &tag, &size))
       
  1117         return GST_FLOW_OK;
       
  1118     } else {
       
  1119       if ((res =
       
  1120               gst_pad_pull_range (wav->sinkpad, wav->offset, 8,
       
  1121                   &buf)) != GST_FLOW_OK)
       
  1122         goto header_read_error;
       
  1123       tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf));
       
  1124       size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 4);
       
  1125     }
       
  1126 
       
  1127     /*
       
  1128        wav is a st00pid format, we don't know for sure where data starts.
       
  1129        So we have to go bit by bit until we find the 'data' header
       
  1130      */
       
  1131 
       
  1132     switch (tag) {
       
  1133         /* TODO : Implement the various cases */
       
  1134       case GST_RIFF_TAG_data:{
       
  1135         gint64 upstream_size;
       
  1136 
       
  1137         GST_DEBUG_OBJECT (wav, "Got 'data' TAG, size : %d", size);
       
  1138         gotdata = TRUE;
       
  1139         if (wav->streaming) {
       
  1140           gst_adapter_flush (wav->adapter, 8);
       
  1141         } else {
       
  1142           gst_buffer_unref (buf);
       
  1143         }
       
  1144         wav->offset += 8;
       
  1145         wav->datastart = wav->offset;
       
  1146         /* file might be truncated */
       
  1147         if (gst_wavparse_get_upstream_size (wav, &upstream_size)) {
       
  1148           size = MIN (size, (upstream_size - wav->datastart));
       
  1149         }
       
  1150         wav->datasize = size;
       
  1151         wav->dataleft = size;
       
  1152         wav->end_offset = size + wav->datastart;
       
  1153         break;
       
  1154       }
       
  1155       default:
       
  1156         if (wav->streaming) {
       
  1157           if (!gst_wavparse_peek_chunk (wav, &tag, &size))
       
  1158             return GST_FLOW_OK;
       
  1159         }
       
  1160         GST_DEBUG_OBJECT (wav, "Ignoring tag %" GST_FOURCC_FORMAT,
       
  1161             GST_FOURCC_ARGS (tag));
       
  1162         wav->offset += 8 + ((size + 1) & ~1);
       
  1163         if (wav->streaming) {
       
  1164           gst_adapter_flush (wav->adapter, 8 + ((size + 1) & ~1));
       
  1165         } else {
       
  1166           gst_buffer_unref (buf);
       
  1167         }
       
  1168     }
       
  1169   }
       
  1170 
       
  1171   GST_DEBUG_OBJECT (wav, "Finished parsing headers");
       
  1172 
       
  1173   duration = gst_util_uint64_scale_int (wav->datasize, GST_SECOND, wav->bps);
       
  1174   GST_DEBUG_OBJECT (wav, "Got duration %" GST_TIME_FORMAT,
       
  1175       GST_TIME_ARGS (duration));
       
  1176   gst_segment_set_duration (&wav->segment, GST_FORMAT_TIME, duration);
       
  1177 
       
  1178   /* now we have all the info to perform a pending seek if any, if no
       
  1179    * event, this will still do the right thing and it will also send
       
  1180    * the right newsegment event downstream. */
       
  1181   gst_wavparse_perform_seek (wav, wav->seek_event);
       
  1182   /* remove pending event */
       
  1183   event_p = &wav->seek_event;
       
  1184   gst_event_replace (event_p, NULL);
       
  1185 
       
  1186   wav->state = GST_WAVPARSE_DATA;
       
  1187 
       
  1188   return GST_FLOW_OK;
       
  1189 
       
  1190   /* ERROR */
       
  1191 invalid_wav:
       
  1192   {
       
  1193     GST_ELEMENT_ERROR (wav, STREAM, DEMUX, (NULL),
       
  1194         ("Invalid WAV header (no fmt at start): %"
       
  1195             GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
       
  1196     g_free (codec_name);
       
  1197 
       
  1198     return GST_FLOW_ERROR;
       
  1199   }
       
  1200 parse_header_error:
       
  1201   {
       
  1202     GST_ELEMENT_ERROR (wav, STREAM, DEMUX, (NULL),
       
  1203         ("Couldn't parse audio header"));
       
  1204     gst_buffer_unref (buf);
       
  1205     g_free (codec_name);
       
  1206  
       
  1207     return GST_FLOW_ERROR;
       
  1208   }
       
  1209 no_channels:
       
  1210   {
       
  1211     GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL),
       
  1212         ("Stream claims to contain no channels - invalid data"));
       
  1213     g_free (header);
       
  1214     g_free (codec_name);
       
  1215     return GST_FLOW_ERROR;
       
  1216   }
       
  1217 no_bitrate:
       
  1218   {
       
  1219     GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL),
       
  1220         ("Stream claims to have a bitrate of <= zero - invalid data"));
       
  1221     g_free (header);
       
  1222     g_free (codec_name);
       
  1223     return GST_FLOW_ERROR;
       
  1224   }
       
  1225 no_bytes_per_sample:
       
  1226   {
       
  1227     GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL),
       
  1228         ("could not caluclate bytes per sample - invalid data"));
       
  1229     g_free (header);
       
  1230     g_free (codec_name);
       
  1231     return GST_FLOW_ERROR;
       
  1232   }
       
  1233 unknown_format:
       
  1234   {
       
  1235     GST_ELEMENT_ERROR (wav, STREAM, TYPE_NOT_FOUND, (NULL),
       
  1236         ("No caps found for format 0x%x, %d channels, %d Hz",
       
  1237             wav->format, wav->channels, wav->rate));
       
  1238     g_free (codec_name);
       
  1239     return GST_FLOW_ERROR;
       
  1240   }
       
  1241 header_read_error:
       
  1242   {
       
  1243     GST_ELEMENT_ERROR (wav, STREAM, DEMUX, (NULL), ("Couldn't read in header"));
       
  1244     g_free (codec_name);
       
  1245     return GST_FLOW_ERROR;
       
  1246   }
       
  1247 }
       
  1248 
       
  1249 
       
  1250 /*                       
       
  1251  * Read WAV file tag when streaming
       
  1252  */
       
  1253 static GstFlowReturn
       
  1254 gst_wavparse_parse_stream_init (GstWavParse * wav)
       
  1255 {
       
  1256   if (gst_adapter_available (wav->adapter) >= 12) {
       
  1257     GstBuffer *tmp = gst_buffer_new ();
       
  1258 
       
  1259     /* _take flushes the data */
       
  1260     GST_BUFFER_DATA (tmp) = gst_adapter_take (wav->adapter, 12);
       
  1261     GST_BUFFER_SIZE (tmp) = 12;
       
  1262 
       
  1263     GST_DEBUG ("Parsing wav header");
       
  1264     if (!gst_wavparse_parse_file_header (GST_ELEMENT (wav), tmp)) {
       
  1265       return GST_FLOW_ERROR;
       
  1266     }
       
  1267 
       
  1268     wav->offset += 12;
       
  1269     /* Go to next state */
       
  1270     wav->state = GST_WAVPARSE_HEADER;
       
  1271   }
       
  1272   return GST_FLOW_OK;
       
  1273 }
       
  1274 
       
  1275 /* handle an event sent directly to the element.
       
  1276  *
       
  1277  * This event can be sent either in the READY state or the
       
  1278  * >READY state. The only event of interest really is the seek
       
  1279  * event.
       
  1280  *
       
  1281  * In the READY state we can only store the event and try to
       
  1282  * respect it when going to PAUSED. We assume we are in the
       
  1283  * READY state when our parsing state != GST_WAVPARSE_DATA.
       
  1284  *
       
  1285  * When we are steaming, we can simply perform the seek right
       
  1286  * away.
       
  1287  */
       
  1288 static gboolean
       
  1289 gst_wavparse_send_event (GstElement * element, GstEvent * event)
       
  1290 {
       
  1291   GstWavParse *wav = GST_WAVPARSE (element);
       
  1292   gboolean res = FALSE;
       
  1293   GstEvent **event_p;
       
  1294 
       
  1295   GST_DEBUG_OBJECT (wav, "received event %s", GST_EVENT_TYPE_NAME (event));
       
  1296 
       
  1297   switch (GST_EVENT_TYPE (event)) {
       
  1298     case GST_EVENT_SEEK:
       
  1299       if (wav->state == GST_WAVPARSE_DATA) {
       
  1300         /* we can handle the seek directly when streaming data */
       
  1301         res = gst_wavparse_perform_seek (wav, event);
       
  1302       } else {
       
  1303         GST_DEBUG_OBJECT (wav, "queuing seek for later");
       
  1304 
       
  1305         event_p = &wav->seek_event;
       
  1306         gst_event_replace (event_p, event);
       
  1307 
       
  1308         /* we always return true */
       
  1309         res = TRUE;
       
  1310       }
       
  1311       break;
       
  1312     default:
       
  1313       break;
       
  1314   }
       
  1315   gst_event_unref (event);
       
  1316   return res;
       
  1317 }
       
  1318 
       
  1319 static void
       
  1320 gst_wavparse_add_src_pad (GstWavParse * wav, GstBuffer * buf)
       
  1321 {
       
  1322   GstStructure *s;
       
  1323   const guint8 dts_marker[] = { 0xFF, 0x1F, 0x00, 0xE8, 0xF1, 0x07 };
       
  1324 
       
  1325   
       
  1326   s = gst_caps_get_structure (wav->caps, 0);
       
  1327   if (gst_structure_has_name (s, "audio/x-raw-int") &&
       
  1328       GST_BUFFER_SIZE (buf) > 6 &&
       
  1329       memcmp (GST_BUFFER_DATA (buf), dts_marker, 6) == 0) {
       
  1330 
       
  1331     GST_WARNING_OBJECT (wav, "Found DTS marker in file marked as raw PCM");
       
  1332     gst_caps_unref (wav->caps);
       
  1333     wav->caps = gst_caps_from_string ("audio/x-dts");
       
  1334 
       
  1335     gst_tag_list_add (wav->tags, GST_TAG_MERGE_REPLACE,
       
  1336         GST_TAG_AUDIO_CODEC, "dts", NULL);
       
  1337   
       
  1338   }
       
  1339 
       
  1340   gst_wavparse_create_sourcepad (wav);
       
  1341   gst_pad_set_active (wav->srcpad, TRUE);
       
  1342   gst_pad_set_caps (wav->srcpad, wav->caps);
       
  1343   gst_caps_replace (&wav->caps, NULL);
       
  1344 
       
  1345   gst_element_add_pad (GST_ELEMENT (wav), wav->srcpad);
       
  1346    
       
  1347 
       
  1348   gst_element_no_more_pads (GST_ELEMENT (wav));
       
  1349 
       
  1350   GST_DEBUG_OBJECT (wav, "Send newsegment event on newpad");
       
  1351   gst_pad_push_event (wav->srcpad, wav->newsegment);
       
  1352   wav->newsegment = NULL;
       
  1353 
       
  1354   
       
  1355   if (wav->tags) {
       
  1356     gst_element_found_tags_for_pad (GST_ELEMENT (wav), wav->srcpad, wav->tags);
       
  1357     wav->tags = NULL;
       
  1358   }
       
  1359 
       
  1360 }
       
  1361 
       
  1362 #define MAX_BUFFER_SIZE 4096
       
  1363 
       
  1364 static GstFlowReturn
       
  1365 gst_wavparse_stream_data (GstWavParse * wav)
       
  1366 {
       
  1367   GstBuffer *buf = NULL;
       
  1368   GstFlowReturn res = GST_FLOW_OK;
       
  1369   guint64 desired, obtained;
       
  1370   GstClockTime timestamp, next_timestamp;
       
  1371   guint64 pos, nextpos;
       
  1372 
       
  1373  
       
  1374 iterate_adapter:
       
  1375   GST_LOG_OBJECT (wav,
       
  1376       "offset: %" G_GINT64_FORMAT " , end: %" G_GINT64_FORMAT " , dataleft: %"
       
  1377       G_GINT64_FORMAT, wav->offset, wav->end_offset, wav->dataleft);
       
  1378 
       
  1379   /* Get the next n bytes and output them */
       
  1380   if (wav->dataleft == 0 || wav->dataleft < wav->blockalign)
       
  1381     goto found_eos;
       
  1382 
       
  1383   /* scale the amount of data by the segment rate so we get equal
       
  1384    * amounts of data regardless of the playback rate */
       
  1385   desired =
       
  1386       MIN (gst_guint64_to_gdouble (wav->dataleft),
       
  1387       MAX_BUFFER_SIZE * ABS (wav->segment.rate));
       
  1388   if (desired >= wav->blockalign && wav->blockalign > 0)
       
  1389     desired -= (desired % wav->blockalign);
       
  1390 
       
  1391   
       
  1392   GST_LOG_OBJECT (wav, "Fetching %" G_GINT64_FORMAT " bytes of data "
       
  1393       "from the sinkpad", desired);
       
  1394 
       
  1395   if (wav->streaming) {
       
  1396     guint avail = gst_adapter_available (wav->adapter);
       
  1397      
       
  1398     if (avail < desired) {
       
  1399    
       
  1400       GST_LOG_OBJECT (wav, "Got only %d bytes of data from the sinkpad", avail);
       
  1401       return GST_FLOW_OK;
       
  1402     }
       
  1403 
       
  1404     buf = gst_buffer_new ();
       
  1405     GST_BUFFER_DATA (buf) = gst_adapter_take (wav->adapter, desired);
       
  1406     GST_BUFFER_SIZE (buf) = desired;
       
  1407 
       
  1408     
       
  1409   } else {
       
  1410     if ((res = gst_pad_pull_range (wav->sinkpad, wav->offset,
       
  1411                 desired, &buf)) != GST_FLOW_OK)
       
  1412         {
       
  1413    
       
  1414       goto pull_error;
       
  1415         }
       
  1416 
       
  1417   }
       
  1418 
       
  1419   /* first chunk of data? create the source pad. We do this only here so
       
  1420    * we can detect broken .wav files with dts disguised as raw PCM (sigh) */
       
  1421   if (G_UNLIKELY (wav->first)) {
       
  1422     wav->first = FALSE;
       
  1423 
       
  1424     gst_wavparse_add_src_pad (wav, buf);
       
  1425   }
       
  1426 
       
  1427   obtained = GST_BUFFER_SIZE (buf);
       
  1428 
       
  1429   /* our positions */
       
  1430   pos = wav->offset - wav->datastart;
       
  1431   nextpos = pos + obtained;
       
  1432 
       
  1433   /* update offsets, does not overflow. */
       
  1434   GST_BUFFER_OFFSET (buf) = pos / wav->bytes_per_sample;
       
  1435   GST_BUFFER_OFFSET_END (buf) = nextpos / wav->bytes_per_sample;
       
  1436 
       
  1437   /* and timestamps, be carefull for overflows */
       
  1438   timestamp = gst_util_uint64_scale_int (pos, GST_SECOND, wav->bps);
       
  1439   next_timestamp = gst_util_uint64_scale_int (nextpos, GST_SECOND, wav->bps);
       
  1440 
       
  1441   GST_BUFFER_TIMESTAMP (buf) = timestamp;
       
  1442   GST_BUFFER_DURATION (buf) = next_timestamp - timestamp;
       
  1443 
       
  1444   /* update current running segment position */
       
  1445   gst_segment_set_last_stop (&wav->segment, GST_FORMAT_TIME, next_timestamp);
       
  1446 
       
  1447   /* don't forget to set the caps on the buffer */
       
  1448   gst_buffer_set_caps (buf, GST_PAD_CAPS (wav->srcpad));
       
  1449 
       
  1450   GST_LOG_OBJECT (wav,
       
  1451       "Got buffer. timestamp:%" GST_TIME_FORMAT " , duration:%" GST_TIME_FORMAT
       
  1452       ", size:%u", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
       
  1453       GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_SIZE (buf));
       
  1454   
       
  1455      
       
  1456   if ((res = gst_pad_push (wav->srcpad, buf)) != GST_FLOW_OK)
       
  1457       {
       
  1458 
       
  1459     goto push_error;
       
  1460       }
       
  1461  
       
  1462     
       
  1463   if (obtained < wav->dataleft) {
       
  1464     wav->dataleft -= obtained;
       
  1465   } else {
       
  1466     wav->dataleft = 0;
       
  1467   }
       
  1468   wav->offset += obtained;
       
  1469   /* Iterate until need more data, so adapter size won't grow */
       
  1470   if (wav->streaming) {
       
  1471     GST_LOG_OBJECT (wav,
       
  1472         "offset: %" G_GINT64_FORMAT " , end: %" G_GINT64_FORMAT, wav->offset,
       
  1473         wav->end_offset);
       
  1474     
       
  1475     goto iterate_adapter;
       
  1476   }
       
  1477 
       
  1478   return res;
       
  1479 
       
  1480   /* ERROR */
       
  1481 found_eos:
       
  1482   {
       
  1483 
       
  1484     GST_DEBUG_OBJECT (wav, "found EOS");
       
  1485     /* we completed the segment */
       
  1486     wav->segment_running = FALSE;
       
  1487     if (wav->segment.flags & GST_SEEK_FLAG_SEGMENT) {
       
  1488       GstClockTime stop;
       
  1489 
       
  1490       if ((stop = wav->segment.stop) == -1)
       
  1491         stop = wav->segment.duration;
       
  1492 
       
  1493       gst_element_post_message (GST_ELEMENT (wav),
       
  1494           gst_message_new_segment_done (GST_OBJECT (wav), GST_FORMAT_TIME,
       
  1495               stop));
       
  1496 
       
  1497     } else {
       
  1498       gst_pad_push_event (wav->srcpad, gst_event_new_eos ());
       
  1499  
       
  1500     }
       
  1501     return GST_FLOW_WRONG_STATE;
       
  1502   }
       
  1503 pull_error:
       
  1504   {
       
  1505      
       
  1506     GST_DEBUG_OBJECT (wav, "Error getting %" G_GINT64_FORMAT " bytes from the "
       
  1507         "sinkpad (dataleft = %" G_GINT64_FORMAT ")", desired, wav->dataleft);
       
  1508     return res;
       
  1509   }
       
  1510 push_error:
       
  1511   {
       
  1512       
       
  1513     GST_DEBUG_OBJECT (wav, "Error pushing on srcpad");
       
  1514     return res;
       
  1515   }
       
  1516 }
       
  1517 
       
  1518 static void
       
  1519 gst_wavparse_loop (GstPad * pad)
       
  1520 {
       
  1521   GstFlowReturn ret;
       
  1522   GstWavParse *wav = GST_WAVPARSE (GST_PAD_PARENT (pad));
       
  1523 
       
  1524   GST_LOG_OBJECT (wav, "process data");
       
  1525 
       
  1526   switch (wav->state) {
       
  1527     case GST_WAVPARSE_START:
       
  1528       GST_DEBUG_OBJECT (wav, "GST_WAVPARSE_START");
       
  1529       if ((ret = gst_wavparse_stream_init (wav)) != GST_FLOW_OK)
       
  1530         goto pause;
       
  1531       
       
  1532       wav->state = GST_WAVPARSE_HEADER;
       
  1533       /* fall-through */
       
  1534 
       
  1535     case GST_WAVPARSE_HEADER:
       
  1536       GST_DEBUG_OBJECT (wav, "GST_WAVPARSE_HEADER");
       
  1537       if ((ret = gst_wavparse_stream_headers (wav)) != GST_FLOW_OK)
       
  1538         goto pause;
       
  1539 
       
  1540       wav->state = GST_WAVPARSE_DATA;
       
  1541       /* fall-through */
       
  1542 
       
  1543     case GST_WAVPARSE_DATA:
       
  1544       if ((ret = gst_wavparse_stream_data (wav)) != GST_FLOW_OK)
       
  1545           {
       
  1546 
       
  1547         goto pause;
       
  1548           }
       
  1549  
       
  1550         break;
       
  1551     default:
       
  1552       g_assert_not_reached ();
       
  1553   }
       
  1554  
       
  1555   return;
       
  1556 
       
  1557   /* ERRORS */
       
  1558 pause:
       
  1559   GST_LOG_OBJECT (wav, "pausing task %d", ret);
       
  1560   gst_pad_pause_task (wav->sinkpad);
       
  1561   if (GST_FLOW_IS_FATAL (ret)) {
       
  1562 
       
  1563      
       
  1564     /* for fatal errors we post an error message */
       
  1565     GST_ELEMENT_ERROR (wav, STREAM, FAILED,
       
  1566         (_("Internal data stream error.")),
       
  1567         ("streaming stopped, reason %s", gst_flow_get_name (ret)));
       
  1568     if (wav->srcpad != NULL)
       
  1569         {
       
  1570       gst_pad_push_event (wav->srcpad, gst_event_new_eos ());
       
  1571            }
       
  1572   }
       
  1573   
       
  1574 }
       
  1575 
       
  1576 static GstFlowReturn
       
  1577 gst_wavparse_chain (GstPad * pad, GstBuffer * buf)
       
  1578 {
       
  1579   GstFlowReturn ret;
       
  1580   GstWavParse *wav = GST_WAVPARSE (GST_PAD_PARENT (pad));
       
  1581    GST_LOG_OBJECT (wav, "adapter_push %" G_GINT64_FORMAT " bytes",
       
  1582       GST_BUFFER_SIZE (buf));
       
  1583 
       
  1584   gst_adapter_push (wav->adapter, buf);
       
  1585   switch (wav->state) {
       
  1586     case GST_WAVPARSE_START:
       
  1587       GST_DEBUG_OBJECT (wav, "GST_WAVPARSE_START");
       
  1588       if ((ret = gst_wavparse_parse_stream_init (wav)) != GST_FLOW_OK) 
       
  1589       {
       
  1590    
       
  1591         goto pause;
       
  1592 			}
       
  1593 			
       
  1594       wav->state = GST_WAVPARSE_HEADER;
       
  1595       /* fall-through */
       
  1596 
       
  1597     case GST_WAVPARSE_HEADER:
       
  1598       GST_DEBUG_OBJECT (wav, "GST_WAVPARSE_HEADER");
       
  1599       if ((ret = gst_wavparse_stream_headers (wav)) != GST_FLOW_OK)
       
  1600         goto pause;
       
  1601 		
       
  1602       wav->state = GST_WAVPARSE_DATA;
       
  1603       /* fall-through */
       
  1604 
       
  1605     case GST_WAVPARSE_DATA:
       
  1606       if ((ret = gst_wavparse_stream_data (wav)) != GST_FLOW_OK)
       
  1607       {
       
  1608  
       
  1609         goto pause;
       
  1610       }
       
  1611 
       
  1612       break;
       
  1613 
       
  1614     default:
       
  1615       g_assert_not_reached ();
       
  1616   }
       
  1617 	
       
  1618   return ret;
       
  1619 
       
  1620 pause:
       
  1621 
       
  1622   GST_LOG_OBJECT (wav, "pausing task %d", ret);
       
  1623   gst_pad_pause_task (wav->sinkpad);
       
  1624   if (GST_FLOW_IS_FATAL (ret)) {
       
  1625     /* for fatal errors we post an error message */
       
  1626  
       
  1627     GST_ELEMENT_ERROR (wav, STREAM, FAILED,
       
  1628         (_("Internal data stream error.")),
       
  1629         ("streaming stopped, reason %s", gst_flow_get_name (ret)));
       
  1630     if (wav->srcpad != NULL)
       
  1631     {
       
  1632       gst_pad_push_event (wav->srcpad, gst_event_new_eos ());
       
  1633   	
       
  1634   	}
       
  1635   }
       
  1636 
       
  1637   return ret;
       
  1638 }
       
  1639 
       
  1640 #if 0
       
  1641 /* convert and query stuff */
       
  1642 static const GstFormat *
       
  1643 gst_wavparse_get_formats (GstPad * pad)
       
  1644 {
       
  1645   static GstFormat formats[] = {
       
  1646     GST_FORMAT_TIME,
       
  1647     GST_FORMAT_BYTES,
       
  1648     GST_FORMAT_DEFAULT,         /* a "frame", ie a set of samples per Hz */
       
  1649     0
       
  1650   };
       
  1651 
       
  1652   return formats;
       
  1653 }
       
  1654 #endif
       
  1655 
       
  1656 static gboolean
       
  1657 gst_wavparse_pad_convert (GstPad * pad,
       
  1658     GstFormat src_format, gint64 src_value,
       
  1659     GstFormat * dest_format, gint64 * dest_value)
       
  1660 {
       
  1661   GstWavParse *wavparse;
       
  1662   gboolean res = TRUE;
       
  1663 
       
  1664   wavparse = GST_WAVPARSE (gst_pad_get_parent (pad));
       
  1665 
       
  1666   if (wavparse->bytes_per_sample == 0)
       
  1667     goto no_bytes_per_sample;
       
  1668 
       
  1669   if (wavparse->bps == 0)
       
  1670     goto no_bps;
       
  1671 
       
  1672   switch (src_format) {
       
  1673     case GST_FORMAT_BYTES:
       
  1674       switch (*dest_format) {
       
  1675         case GST_FORMAT_DEFAULT:
       
  1676           *dest_value = src_value / wavparse->bytes_per_sample;
       
  1677           break;
       
  1678         case GST_FORMAT_TIME:
       
  1679           *dest_value =
       
  1680               gst_util_uint64_scale_int (src_value, GST_SECOND, wavparse->bps);
       
  1681           break;
       
  1682         default:
       
  1683           res = FALSE;
       
  1684           goto done;
       
  1685       }
       
  1686       *dest_value -= *dest_value % wavparse->bytes_per_sample;
       
  1687       break;
       
  1688 
       
  1689     case GST_FORMAT_DEFAULT:
       
  1690       switch (*dest_format) {
       
  1691         case GST_FORMAT_BYTES:
       
  1692           *dest_value = src_value * wavparse->bytes_per_sample;
       
  1693           break;
       
  1694         case GST_FORMAT_TIME:
       
  1695           *dest_value =
       
  1696               gst_util_uint64_scale_int (src_value, GST_SECOND, wavparse->rate);
       
  1697           break;
       
  1698         default:
       
  1699           res = FALSE;
       
  1700           goto done;
       
  1701       }
       
  1702       break;
       
  1703 
       
  1704     case GST_FORMAT_TIME:
       
  1705       switch (*dest_format) {
       
  1706         case GST_FORMAT_BYTES:
       
  1707           /* make sure we end up on a sample boundary */
       
  1708           *dest_value =
       
  1709               gst_util_uint64_scale_int (src_value, wavparse->bps, GST_SECOND);
       
  1710           *dest_value -= *dest_value % wavparse->blockalign;
       
  1711           break;
       
  1712         case GST_FORMAT_DEFAULT:
       
  1713           *dest_value =
       
  1714               gst_util_uint64_scale_int (src_value, wavparse->rate, GST_SECOND);
       
  1715           break;
       
  1716         default:
       
  1717           res = FALSE;
       
  1718           goto done;
       
  1719       }
       
  1720       break;
       
  1721 
       
  1722     default:
       
  1723       res = FALSE;
       
  1724       goto done;
       
  1725   }
       
  1726 
       
  1727 done:
       
  1728   gst_object_unref (wavparse);
       
  1729 
       
  1730   return res;
       
  1731 
       
  1732   /* ERRORS */
       
  1733 no_bytes_per_sample:
       
  1734   {
       
  1735     GST_DEBUG_OBJECT (wavparse,
       
  1736         "bytes_per_sample 0, probably an mp3 - channels %d, width %d",
       
  1737         wavparse->channels, wavparse->width);
       
  1738     res = FALSE;
       
  1739     goto done;
       
  1740   }
       
  1741 no_bps:
       
  1742   {
       
  1743     GST_DEBUG_OBJECT (wavparse, "bps 0, cannot convert");
       
  1744     res = FALSE;
       
  1745     goto done;
       
  1746   }
       
  1747 }
       
  1748 
       
  1749 static const GstQueryType *
       
  1750 gst_wavparse_get_query_types (GstPad * pad)
       
  1751 {
       
  1752   static const GstQueryType types[] = {
       
  1753     GST_QUERY_POSITION,
       
  1754     GST_QUERY_DURATION,
       
  1755     GST_QUERY_CONVERT,
       
  1756     0
       
  1757   };
       
  1758 
       
  1759   return types;
       
  1760 }
       
  1761 
       
  1762 /* handle queries for location and length in requested format */
       
  1763 static gboolean
       
  1764 gst_wavparse_pad_query (GstPad * pad, GstQuery * query)
       
  1765 {
       
  1766   gboolean res = TRUE;
       
  1767   GstWavParse *wav = GST_WAVPARSE (GST_PAD_PARENT (pad));
       
  1768 
       
  1769   /* only if we know */
       
  1770   if (wav->state != GST_WAVPARSE_DATA)
       
  1771     return FALSE;
       
  1772 
       
  1773   switch (GST_QUERY_TYPE (query)) {
       
  1774     case GST_QUERY_POSITION:
       
  1775     {
       
  1776       gint64 curb;
       
  1777       gint64 cur;
       
  1778       GstFormat format;
       
  1779       gboolean res = TRUE;
       
  1780 
       
  1781       curb = wav->offset - wav->datastart;
       
  1782       gst_query_parse_position (query, &format, NULL);
       
  1783 
       
  1784       switch (format) {
       
  1785         case GST_FORMAT_TIME:
       
  1786           res &=
       
  1787               gst_wavparse_pad_convert (pad, GST_FORMAT_BYTES, curb,
       
  1788               &format, &cur);
       
  1789           break;
       
  1790         default:
       
  1791           format = GST_FORMAT_BYTES;
       
  1792           cur = curb;
       
  1793           break;
       
  1794       }
       
  1795       if (res)
       
  1796         gst_query_set_position (query, format, cur);
       
  1797       break;
       
  1798     }
       
  1799     case GST_QUERY_DURATION:
       
  1800     {
       
  1801       gint64 endb;
       
  1802       gint64 end;
       
  1803       GstFormat format;
       
  1804       gboolean res = TRUE;
       
  1805 
       
  1806       endb = wav->datasize;
       
  1807       gst_query_parse_duration (query, &format, NULL);
       
  1808 
       
  1809       switch (format) {
       
  1810         case GST_FORMAT_TIME:
       
  1811           res &=
       
  1812               gst_wavparse_pad_convert (pad, GST_FORMAT_BYTES, endb,
       
  1813               &format, &end);
       
  1814           break;
       
  1815         default:
       
  1816           format = GST_FORMAT_BYTES;
       
  1817           end = endb;
       
  1818           break;
       
  1819       }
       
  1820       if (res)
       
  1821         gst_query_set_duration (query, format, end);
       
  1822       break;
       
  1823     }
       
  1824     case GST_QUERY_CONVERT:
       
  1825     {
       
  1826       gint64 srcvalue, dstvalue;
       
  1827       GstFormat srcformat, dstformat;
       
  1828 
       
  1829       gst_query_parse_convert (query, &srcformat, &srcvalue,
       
  1830           &dstformat, &dstvalue);
       
  1831       res &=
       
  1832           gst_wavparse_pad_convert (pad, srcformat, srcvalue,
       
  1833           &dstformat, &dstvalue);
       
  1834       if (res)
       
  1835         gst_query_set_convert (query, srcformat, srcvalue, dstformat, dstvalue);
       
  1836       break;
       
  1837     }
       
  1838     default:
       
  1839       res = gst_pad_query_default (pad, query);
       
  1840       break;
       
  1841   }
       
  1842   return res;
       
  1843 }
       
  1844 
       
  1845 static gboolean
       
  1846 gst_wavparse_srcpad_event (GstPad * pad, GstEvent * event)
       
  1847 {
       
  1848   GstWavParse *wavparse = GST_WAVPARSE (GST_PAD_PARENT (pad));
       
  1849   gboolean res = TRUE;
       
  1850 
       
  1851   GST_DEBUG_OBJECT (wavparse, "event %d, %s", GST_EVENT_TYPE (event),
       
  1852       GST_EVENT_TYPE_NAME (event));
       
  1853 
       
  1854   /* can only handle events when we are in the data state */
       
  1855   if (wavparse->state != GST_WAVPARSE_DATA)
       
  1856     return FALSE;
       
  1857 
       
  1858   switch (GST_EVENT_TYPE (event)) {
       
  1859     case GST_EVENT_SEEK:
       
  1860     {
       
  1861       res = gst_wavparse_perform_seek (wavparse, event);
       
  1862       break;
       
  1863     }
       
  1864     default:
       
  1865       res = FALSE;
       
  1866       break;
       
  1867   }
       
  1868 
       
  1869   gst_event_unref (event);
       
  1870 
       
  1871   return res;
       
  1872 }
       
  1873 
       
  1874 static gboolean
       
  1875 gst_wavparse_sink_activate (GstPad * sinkpad)
       
  1876 {
       
  1877   GstWavParse *wav = GST_WAVPARSE (gst_pad_get_parent (sinkpad));
       
  1878   gboolean res;
       
  1879 
       
  1880   if (gst_pad_check_pull_range (sinkpad)) {
       
  1881     GST_DEBUG ("going to pull mode");
       
  1882     wav->streaming = FALSE;
       
  1883     wav->adapter = NULL;
       
  1884     res = gst_pad_activate_pull (sinkpad, TRUE);
       
  1885   } else {
       
  1886     GST_DEBUG ("going to push (streaming) mode");
       
  1887     wav->streaming = TRUE;
       
  1888     wav->adapter = gst_adapter_new ();
       
  1889     res = gst_pad_activate_push (sinkpad, TRUE);
       
  1890   }
       
  1891   gst_object_unref (wav);
       
  1892   return res;
       
  1893 }
       
  1894 
       
  1895 
       
  1896 static gboolean
       
  1897 gst_wavparse_sink_activate_pull (GstPad * sinkpad, gboolean active)
       
  1898 {
       
  1899   GstWavParse *wav = GST_WAVPARSE (gst_pad_get_parent (sinkpad));
       
  1900 
       
  1901   GST_DEBUG_OBJECT (wav, "activating pull");
       
  1902 
       
  1903   if (active) {
       
  1904     /* if we have a scheduler we can start the task */
       
  1905     wav->segment_running = TRUE;
       
  1906     gst_pad_start_task (sinkpad, (GstTaskFunction) gst_wavparse_loop, sinkpad);
       
  1907   } else {
       
  1908     gst_pad_stop_task (sinkpad);
       
  1909   }
       
  1910   gst_object_unref (wav);
       
  1911 
       
  1912   return TRUE;
       
  1913 }
       
  1914 
       
  1915 static GstStateChangeReturn
       
  1916 gst_wavparse_change_state (GstElement * element, GstStateChange transition)
       
  1917 {
       
  1918   GstStateChangeReturn ret;
       
  1919   GstWavParse *wav = GST_WAVPARSE (element);
       
  1920 
       
  1921   GST_DEBUG_OBJECT (wav, "changing state %s - %s",
       
  1922       gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
       
  1923       gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
       
  1924 
       
  1925   switch (transition) {
       
  1926     case GST_STATE_CHANGE_NULL_TO_READY:
       
  1927       break;
       
  1928     case GST_STATE_CHANGE_READY_TO_PAUSED:
       
  1929       gst_wavparse_reset (wav);
       
  1930       break;
       
  1931     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
       
  1932       break;
       
  1933     default:
       
  1934       break;
       
  1935   }
       
  1936 
       
  1937   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
       
  1938 
       
  1939   switch (transition) {
       
  1940     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
       
  1941       break;
       
  1942     case GST_STATE_CHANGE_PAUSED_TO_READY:{
       
  1943       GstEvent **event_p = &wav->seek_event;
       
  1944 
       
  1945       gst_wavparse_destroy_sourcepad (wav);
       
  1946       gst_event_replace (event_p, NULL);
       
  1947       gst_wavparse_reset (wav);
       
  1948       if (wav->adapter) {
       
  1949         gst_adapter_clear (wav->adapter);
       
  1950       }
       
  1951       break;
       
  1952     }
       
  1953     case GST_STATE_CHANGE_READY_TO_NULL:
       
  1954       break;
       
  1955     default:
       
  1956       break;
       
  1957   }
       
  1958   return ret;
       
  1959 }
       
  1960 
       
  1961 static gboolean
       
  1962 plugin_init (GstPlugin * plugin)
       
  1963 {
       
  1964   gst_riff_init ();
       
  1965 
       
  1966   GST_DEBUG_CATEGORY_INIT (wavparse_debug, "wavparse", 0, "WAV parser");
       
  1967 
       
  1968   return gst_element_register (plugin, "wavparse", GST_RANK_PRIMARY,
       
  1969       GST_TYPE_WAVPARSE);
       
  1970 }
       
  1971 
       
  1972 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
       
  1973     GST_VERSION_MINOR,
       
  1974     "wavparse",
       
  1975     "Parse a .wav file into raw audio",
       
  1976     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
       
  1977 
       
  1978 
       
  1979 EXPORT_C GstPluginDesc* _GST_PLUGIN_DESC()
       
  1980 {
       
  1981 	return &gst_plugin_desc;
       
  1982 }
       
  1983