gst_plugins_good/gst/auparse/gstauparse.c
changeset 27 d43ce56a1534
parent 23 29ecd5cb86b3
child 31 aec498aab1d3
equal deleted inserted replaced
23:29ecd5cb86b3 27:d43ce56a1534
     1 /* GStreamer
       
     2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
       
     3  * Copyright (C) <2006> Tim-Philipp Müller <tim centricular net>
       
     4  *
       
     5  * This library is free software; you can redistribute it and/or
       
     6  * modify it under the terms of the GNU Library General Public
       
     7  * License as published by the Free Software Foundation; either
       
     8  * version 2 of the License, or (at your option) any later version.
       
     9  *
       
    10  * This library is distributed in the hope that it will be useful,
       
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    13  * Library General Public License for more details.
       
    14  *
       
    15  * You should have received a copy of the GNU Library General Public
       
    16  * License along with this library; if not, write to the
       
    17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    18  * Boston, MA 02111-1307, USA.
       
    19  */
       
    20 
       
    21 /**
       
    22  * SECTION:element-auparse
       
    23  *
       
    24  * Parses .au files mostly originating from sun os based computers.
       
    25  */
       
    26 
       
    27 #ifdef HAVE_CONFIG_H
       
    28 #include "config.h"
       
    29 #endif
       
    30 
       
    31 #include <stdlib.h>
       
    32 #include <string.h>
       
    33 
       
    34 #include "gstauparse.h"
       
    35 #include <gst/audio/audio.h>
       
    36 
       
    37 GST_DEBUG_CATEGORY_STATIC (auparse_debug);
       
    38 #define GST_CAT_DEFAULT (auparse_debug)
       
    39 
       
    40 static const GstElementDetails gst_au_parse_details =
       
    41 GST_ELEMENT_DETAILS ("AU audio demuxer",
       
    42     "Codec/Demuxer/Audio",
       
    43     "Parse an .au file into raw audio",
       
    44     "Erik Walthinsen <omega@cse.ogi.edu>");
       
    45 
       
    46 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
       
    47     GST_PAD_SINK,
       
    48     GST_PAD_ALWAYS,
       
    49     GST_STATIC_CAPS ("audio/x-au")
       
    50     );
       
    51 
       
    52 #define GST_AU_PARSE_ALAW_PAD_TEMPLATE_CAPS \
       
    53     "audio/x-alaw, "                        \
       
    54     "rate = (int) [ 8000, 192000 ], "       \
       
    55     "channels = (int) [ 1, 2 ]"
       
    56 
       
    57 #define GST_AU_PARSE_MULAW_PAD_TEMPLATE_CAPS \
       
    58     "audio/x-mulaw, "                        \
       
    59     "rate = (int) [ 8000, 192000 ], "        \
       
    60     "channels = (int) [ 1, 2 ]"
       
    61 
       
    62 /* Nothing to decode those ADPCM streams for now */
       
    63 #define GST_AU_PARSE_ADPCM_PAD_TEMPLATE_CAPS \
       
    64     "audio/x-adpcm, "                        \
       
    65     "layout = (string) { g721, g722, g723_3, g723_5 }"
       
    66 
       
    67 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
       
    68     GST_PAD_SRC,
       
    69     GST_PAD_SOMETIMES,
       
    70     GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS "; "
       
    71         GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS ";"
       
    72         GST_AU_PARSE_ALAW_PAD_TEMPLATE_CAPS ";"
       
    73         GST_AU_PARSE_MULAW_PAD_TEMPLATE_CAPS ";"
       
    74         GST_AU_PARSE_ADPCM_PAD_TEMPLATE_CAPS));
       
    75 
       
    76 
       
    77 static void gst_au_parse_dispose (GObject * object);
       
    78 static GstFlowReturn gst_au_parse_chain (GstPad * pad, GstBuffer * buf);
       
    79 static GstStateChangeReturn gst_au_parse_change_state (GstElement * element,
       
    80     GstStateChange transition);
       
    81 static void gst_au_parse_reset (GstAuParse * auparse);
       
    82 static gboolean gst_au_parse_remove_srcpad (GstAuParse * auparse);
       
    83 static gboolean gst_au_parse_add_srcpad (GstAuParse * auparse, GstCaps * caps);
       
    84 static gboolean gst_au_parse_src_query (GstPad * pad, GstQuery * query);
       
    85 static gboolean gst_au_parse_src_event (GstPad * pad, GstEvent * event);
       
    86 static gboolean gst_au_parse_sink_event (GstPad * pad, GstEvent * event);
       
    87 
       
    88 GST_BOILERPLATE (GstAuParse, gst_au_parse, GstElement, GST_TYPE_ELEMENT);
       
    89 
       
    90 static void
       
    91 gst_au_parse_base_init (gpointer g_class)
       
    92 {
       
    93   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
       
    94 
       
    95   gst_element_class_add_pad_template (element_class,
       
    96       gst_static_pad_template_get (&sink_template));
       
    97   gst_element_class_add_pad_template (element_class,
       
    98       gst_static_pad_template_get (&src_template));
       
    99   gst_element_class_set_details (element_class, &gst_au_parse_details);
       
   100 
       
   101   GST_DEBUG_CATEGORY_INIT (auparse_debug, "auparse", 0, ".au parser");
       
   102 }
       
   103 
       
   104 static void
       
   105 gst_au_parse_class_init (GstAuParseClass * klass)
       
   106 {
       
   107   GObjectClass *gobject_class;
       
   108   GstElementClass *gstelement_class;
       
   109 
       
   110   gobject_class = (GObjectClass *) klass;
       
   111   gstelement_class = (GstElementClass *) klass;
       
   112 
       
   113   gobject_class->dispose = gst_au_parse_dispose;
       
   114 
       
   115   gstelement_class->change_state =
       
   116       GST_DEBUG_FUNCPTR (gst_au_parse_change_state);
       
   117 }
       
   118 
       
   119 static void
       
   120 gst_au_parse_init (GstAuParse * auparse, GstAuParseClass * klass)
       
   121 {
       
   122   auparse->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
       
   123   gst_pad_set_chain_function (auparse->sinkpad,
       
   124       GST_DEBUG_FUNCPTR (gst_au_parse_chain));
       
   125   gst_pad_set_event_function (auparse->sinkpad,
       
   126       GST_DEBUG_FUNCPTR (gst_au_parse_sink_event));
       
   127   gst_element_add_pad (GST_ELEMENT (auparse), auparse->sinkpad);
       
   128 
       
   129   auparse->srcpad = NULL;
       
   130   auparse->adapter = gst_adapter_new ();
       
   131   gst_au_parse_reset (auparse);
       
   132 }
       
   133 
       
   134 static void
       
   135 gst_au_parse_dispose (GObject * object)
       
   136 {
       
   137   GstAuParse *au = GST_AU_PARSE (object);
       
   138 
       
   139   if (au->adapter != NULL) {
       
   140     g_object_unref (au->adapter);
       
   141     au->adapter = NULL;
       
   142   }
       
   143   G_OBJECT_CLASS (parent_class)->dispose (object);
       
   144 }
       
   145 
       
   146 static void
       
   147 gst_au_parse_reset (GstAuParse * auparse)
       
   148 {
       
   149   gst_au_parse_remove_srcpad (auparse);
       
   150 
       
   151   auparse->offset = 0;
       
   152   auparse->buffer_offset = 0;
       
   153   auparse->encoding = 0;
       
   154   auparse->samplerate = 0;
       
   155   auparse->channels = 0;
       
   156 
       
   157   gst_adapter_clear (auparse->adapter);
       
   158 
       
   159   /* gst_segment_init (&auparse->segment, GST_FORMAT_TIME); */
       
   160 }
       
   161 
       
   162 static gboolean
       
   163 gst_au_parse_add_srcpad (GstAuParse * auparse, GstCaps * new_caps)
       
   164 {
       
   165   if (auparse->src_caps && gst_caps_is_equal (new_caps, auparse->src_caps)) {
       
   166     GST_LOG_OBJECT (auparse, "same caps, nothing to do");
       
   167     return TRUE;
       
   168   }
       
   169 
       
   170   gst_caps_replace (&auparse->src_caps, new_caps);
       
   171   if (auparse->srcpad != NULL) {
       
   172     GST_DEBUG_OBJECT (auparse, "Changing src pad caps to %" GST_PTR_FORMAT,
       
   173         auparse->src_caps);
       
   174     gst_pad_set_caps (auparse->srcpad, auparse->src_caps);
       
   175   }
       
   176 
       
   177   if (auparse->srcpad == NULL) {
       
   178     auparse->srcpad = gst_pad_new_from_static_template (&src_template, "src");
       
   179     g_return_val_if_fail (auparse->srcpad != NULL, FALSE);
       
   180 
       
   181 #if 0
       
   182     gst_pad_set_query_type_function (auparse->srcpad,
       
   183         GST_DEBUG_FUNCPTR (gst_au_parse_src_get_query_types));
       
   184 #endif
       
   185     gst_pad_set_query_function (auparse->srcpad,
       
   186         GST_DEBUG_FUNCPTR (gst_au_parse_src_query));
       
   187     gst_pad_set_event_function (auparse->srcpad,
       
   188         GST_DEBUG_FUNCPTR (gst_au_parse_src_event));
       
   189 
       
   190     gst_pad_use_fixed_caps (auparse->srcpad);
       
   191     gst_pad_set_active (auparse->srcpad, TRUE);
       
   192 
       
   193     if (auparse->src_caps)
       
   194       gst_pad_set_caps (auparse->srcpad, auparse->src_caps);
       
   195 
       
   196     GST_DEBUG_OBJECT (auparse, "Adding src pad with caps %" GST_PTR_FORMAT,
       
   197         auparse->src_caps);
       
   198 
       
   199     gst_object_ref (auparse->srcpad);
       
   200     if (!gst_element_add_pad (GST_ELEMENT (auparse), auparse->srcpad))
       
   201       return FALSE;
       
   202     gst_element_no_more_pads (GST_ELEMENT (auparse));
       
   203   }
       
   204 
       
   205   return TRUE;
       
   206 }
       
   207 
       
   208 static gboolean
       
   209 gst_au_parse_remove_srcpad (GstAuParse * auparse)
       
   210 {
       
   211   gboolean res = TRUE;
       
   212 
       
   213   if (auparse->srcpad != NULL) {
       
   214     GST_DEBUG_OBJECT (auparse, "Removing src pad");
       
   215     res = gst_element_remove_pad (GST_ELEMENT (auparse), auparse->srcpad);
       
   216     g_return_val_if_fail (res != FALSE, FALSE);
       
   217     gst_object_unref (auparse->srcpad);
       
   218     auparse->srcpad = NULL;
       
   219   }
       
   220 
       
   221   return res;
       
   222 }
       
   223 
       
   224 static GstFlowReturn
       
   225 gst_au_parse_parse_header (GstAuParse * auparse)
       
   226 {
       
   227   GstCaps *tempcaps;
       
   228   guint32 size;
       
   229   guint8 *head;
       
   230   gchar layout[7] = { 0, };
       
   231   gint law = 0, depth = 0, ieee = 0;
       
   232 
       
   233   head = (guint8 *) gst_adapter_peek (auparse->adapter, 24);
       
   234   g_assert (head != NULL);
       
   235 
       
   236   GST_DEBUG_OBJECT (auparse, "[%c%c%c%c]", head[0], head[1], head[2], head[3]);
       
   237 
       
   238   switch (GST_READ_UINT32_BE (head)) {
       
   239       /* normal format is big endian (au is a Sparc format) */
       
   240     case 0x2e736e64:{          /* ".snd" */
       
   241       auparse->endianness = G_BIG_ENDIAN;
       
   242       break;
       
   243     }
       
   244       /* and of course, someone had to invent a little endian
       
   245        * version.  Used by DEC systems. */
       
   246     case 0x646e732e:           /* dns.                          */
       
   247     case 0x0064732e:{          /* other source say it is "dns." */
       
   248       auparse->endianness = G_LITTLE_ENDIAN;
       
   249       break;
       
   250     }
       
   251     default:{
       
   252       goto unknown_header;
       
   253     }
       
   254   }
       
   255 
       
   256   auparse->offset = GST_READ_UINT32_BE (head + 4);
       
   257   /* Do not trust size, could be set to -1 : unknown */
       
   258   size = GST_READ_UINT32_BE (head + 8);
       
   259   auparse->encoding = GST_READ_UINT32_BE (head + 12);
       
   260   auparse->samplerate = GST_READ_UINT32_BE (head + 16);
       
   261   auparse->channels = GST_READ_UINT32_BE (head + 20);
       
   262 
       
   263   if (auparse->samplerate < 8000 || auparse->samplerate > 192000)
       
   264     goto unsupported_sample_rate;
       
   265 
       
   266   if (auparse->channels < 1 || auparse->channels > 2)
       
   267     goto unsupported_number_of_channels;
       
   268 
       
   269   GST_DEBUG_OBJECT (auparse, "offset %" G_GINT64_FORMAT ", size %u, "
       
   270       "encoding %u, frequency %u, channels %u", auparse->offset, size,
       
   271       auparse->encoding, auparse->samplerate, auparse->channels);
       
   272 
       
   273   /* Docs:
       
   274    * http://www.opengroup.org/public/pubs/external/auformat.html
       
   275    * http://astronomy.swin.edu.au/~pbourke/dataformats/au/
       
   276    * Solaris headers : /usr/include/audio/au.h
       
   277    * libsndfile : src/au.c
       
   278    *
       
   279    * Samples :
       
   280    * http://www.tsp.ece.mcgill.ca/MMSP/Documents/AudioFormats/AU/Samples.html
       
   281    */
       
   282 
       
   283   switch (auparse->encoding) {
       
   284     case 1:                    /* 8-bit ISDN mu-law G.711 */
       
   285       law = 1;
       
   286       depth = 8;
       
   287       break;
       
   288     case 27:                   /* 8-bit ISDN  A-law G.711 */
       
   289       law = 2;
       
   290       depth = 8;
       
   291       break;
       
   292 
       
   293     case 2:                    /*  8-bit linear PCM */
       
   294       depth = 8;
       
   295       break;
       
   296     case 3:                    /* 16-bit linear PCM */
       
   297       depth = 16;
       
   298       break;
       
   299     case 4:                    /* 24-bit linear PCM */
       
   300       depth = 24;
       
   301       break;
       
   302     case 5:                    /* 32-bit linear PCM */
       
   303       depth = 32;
       
   304       break;
       
   305 
       
   306     case 6:                    /* 32-bit IEEE floating point */
       
   307       ieee = 1;
       
   308       depth = 32;
       
   309       break;
       
   310     case 7:                    /* 64-bit IEEE floating point */
       
   311       ieee = 1;
       
   312       depth = 64;
       
   313       break;
       
   314 
       
   315     case 23:                   /* 4-bit CCITT G.721   ADPCM 32kbps -> modplug/libsndfile (compressed 8-bit mu-law) */
       
   316       strcpy (layout, "g721");
       
   317       break;
       
   318     case 24:                   /* 8-bit CCITT G.722   ADPCM        -> rtp */
       
   319       strcpy (layout, "g722");
       
   320       break;
       
   321     case 25:                   /* 3-bit CCITT G.723.3 ADPCM 24kbps -> rtp/xine/modplug/libsndfile */
       
   322       strcpy (layout, "g723_3");
       
   323       break;
       
   324     case 26:                   /* 5-bit CCITT G.723.5 ADPCM 40kbps -> rtp/xine/modplug/libsndfile */
       
   325       strcpy (layout, "g723_5");
       
   326       break;
       
   327 
       
   328     case 8:                    /* Fragmented sample data */
       
   329     case 9:                    /* AU_ENCODING_NESTED */
       
   330 
       
   331     case 10:                   /* DSP program */
       
   332     case 11:                   /* DSP  8-bit fixed point */
       
   333     case 12:                   /* DSP 16-bit fixed point */
       
   334     case 13:                   /* DSP 24-bit fixed point */
       
   335     case 14:                   /* DSP 32-bit fixed point */
       
   336 
       
   337     case 16:                   /* AU_ENCODING_DISPLAY : non-audio display data */
       
   338     case 17:                   /* AU_ENCODING_MULAW_SQUELCH */
       
   339 
       
   340     case 18:                   /* 16-bit linear with emphasis */
       
   341     case 19:                   /* 16-bit linear compressed (NeXT) */
       
   342     case 20:                   /* 16-bit linear with emphasis and compression */
       
   343 
       
   344     case 21:                   /* Music kit DSP commands */
       
   345     case 22:                   /* Music kit DSP commands samples */
       
   346 
       
   347     default:
       
   348       goto unknown_format;
       
   349   }
       
   350 
       
   351   if (law) {
       
   352     tempcaps =
       
   353         gst_caps_new_simple ((law == 1) ? "audio/x-mulaw" : "audio/x-alaw",
       
   354         "rate", G_TYPE_INT, auparse->samplerate,
       
   355         "channels", G_TYPE_INT, auparse->channels, NULL);
       
   356     auparse->sample_size = auparse->channels;
       
   357   } else if (ieee) {
       
   358     tempcaps = gst_caps_new_simple ("audio/x-raw-float",
       
   359         "rate", G_TYPE_INT, auparse->samplerate,
       
   360         "channels", G_TYPE_INT, auparse->channels,
       
   361         "endianness", G_TYPE_INT, auparse->endianness,
       
   362         "width", G_TYPE_INT, depth, NULL);
       
   363     auparse->sample_size = auparse->channels * depth / 8;
       
   364   } else if (layout[0]) {
       
   365     tempcaps = gst_caps_new_simple ("audio/x-adpcm",
       
   366         "layout", G_TYPE_STRING, layout, NULL);
       
   367     auparse->sample_size = 0;
       
   368   } else {
       
   369     tempcaps = gst_caps_new_simple ("audio/x-raw-int",
       
   370         "rate", G_TYPE_INT, auparse->samplerate,
       
   371         "channels", G_TYPE_INT, auparse->channels,
       
   372         "endianness", G_TYPE_INT, auparse->endianness,
       
   373         "depth", G_TYPE_INT, depth, "width", G_TYPE_INT, depth,
       
   374         /* FIXME: signed TRUE even for 8-bit PCM? */
       
   375         "signed", G_TYPE_BOOLEAN, TRUE, NULL);
       
   376     auparse->sample_size = auparse->channels * depth / 8;
       
   377   }
       
   378 
       
   379   GST_DEBUG_OBJECT (auparse, "sample_size=%d", auparse->sample_size);
       
   380 
       
   381   if (!gst_au_parse_add_srcpad (auparse, tempcaps))
       
   382     goto add_pad_failed;
       
   383 
       
   384   GST_DEBUG_OBJECT (auparse, "offset=%" G_GINT64_FORMAT, auparse->offset);
       
   385   gst_adapter_flush (auparse->adapter, auparse->offset);
       
   386 
       
   387   gst_caps_unref (tempcaps);
       
   388   return GST_FLOW_OK;
       
   389 
       
   390   /* ERRORS */
       
   391 unknown_header:
       
   392   {
       
   393     GST_ELEMENT_ERROR (auparse, STREAM, WRONG_TYPE, (NULL), (NULL));
       
   394     return GST_FLOW_ERROR;
       
   395   }
       
   396 unsupported_sample_rate:
       
   397   {
       
   398     GST_ELEMENT_ERROR (auparse, STREAM, FORMAT, (NULL),
       
   399         ("Unsupported samplerate: %u", auparse->samplerate));
       
   400     return GST_FLOW_ERROR;
       
   401   }
       
   402 unsupported_number_of_channels:
       
   403   {
       
   404     GST_ELEMENT_ERROR (auparse, STREAM, FORMAT, (NULL),
       
   405         ("Unsupported number of channels: %u", auparse->channels));
       
   406     return GST_FLOW_ERROR;
       
   407   }
       
   408 unknown_format:
       
   409   {
       
   410     GST_ELEMENT_ERROR (auparse, STREAM, FORMAT, (NULL),
       
   411         ("Unsupported encoding: %u", auparse->encoding));
       
   412     return GST_FLOW_ERROR;
       
   413   }
       
   414 add_pad_failed:
       
   415   {
       
   416     GST_ELEMENT_ERROR (auparse, STREAM, FAILED, (NULL),
       
   417         ("Failed to add srcpad"));
       
   418     gst_caps_unref (tempcaps);
       
   419     return GST_FLOW_ERROR;
       
   420   }
       
   421 }
       
   422 
       
   423 #define AU_HEADER_SIZE 24
       
   424 
       
   425 static GstFlowReturn
       
   426 gst_au_parse_chain (GstPad * pad, GstBuffer * buf)
       
   427 {
       
   428   GstFlowReturn ret = GST_FLOW_OK;
       
   429   GstAuParse *auparse;
       
   430   gint avail, sendnow = 0;
       
   431 
       
   432   auparse = GST_AU_PARSE (gst_pad_get_parent (pad));
       
   433 
       
   434   GST_LOG_OBJECT (auparse, "got buffer of size %u", GST_BUFFER_SIZE (buf));
       
   435 
       
   436   gst_adapter_push (auparse->adapter, buf);
       
   437   buf = NULL;
       
   438 
       
   439   /* if we haven't seen any data yet... */
       
   440   if (auparse->srcpad == NULL) {
       
   441     if (gst_adapter_available (auparse->adapter) < AU_HEADER_SIZE) {
       
   442       GST_DEBUG_OBJECT (auparse, "need more data to parse header");
       
   443       ret = GST_FLOW_OK;
       
   444       goto out;
       
   445     }
       
   446 
       
   447     ret = gst_au_parse_parse_header (auparse);
       
   448     if (ret != GST_FLOW_OK)
       
   449       goto out;
       
   450 
       
   451     gst_pad_push_event (auparse->srcpad,
       
   452         gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_DEFAULT,
       
   453             0, GST_CLOCK_TIME_NONE, 0));
       
   454   }
       
   455 
       
   456   avail = gst_adapter_available (auparse->adapter);
       
   457 
       
   458   if (auparse->sample_size > 0) {
       
   459     /* Ensure we push a buffer that's a multiple of the frame size downstream */
       
   460     sendnow = avail - (avail % auparse->sample_size);
       
   461   } else {
       
   462     /* It's something non-trivial (such as ADPCM), we don't understand it, so
       
   463      * just push downstream and assume it will know what to do with it */
       
   464     sendnow = avail;
       
   465   }
       
   466 
       
   467   if (sendnow > 0) {
       
   468     GstBuffer *outbuf;
       
   469     const guint8 *data;
       
   470 
       
   471     ret = gst_pad_alloc_buffer_and_set_caps (auparse->srcpad,
       
   472         auparse->buffer_offset, sendnow, GST_PAD_CAPS (auparse->srcpad),
       
   473         &outbuf);
       
   474 
       
   475     if (ret != GST_FLOW_OK) {
       
   476       GST_DEBUG_OBJECT (auparse, "pad alloc flow: %s", gst_flow_get_name (ret));
       
   477       goto out;
       
   478     }
       
   479 
       
   480     data = gst_adapter_peek (auparse->adapter, sendnow);
       
   481     memcpy (GST_BUFFER_DATA (outbuf), data, sendnow);
       
   482     gst_adapter_flush (auparse->adapter, sendnow);
       
   483 
       
   484     auparse->buffer_offset += sendnow;
       
   485 
       
   486     ret = gst_pad_push (auparse->srcpad, outbuf);
       
   487   }
       
   488 
       
   489 out:
       
   490 
       
   491   gst_object_unref (auparse);
       
   492   return ret;
       
   493 }
       
   494 
       
   495 static gboolean
       
   496 gst_au_parse_src_convert (GstAuParse * auparse, GstFormat src_format,
       
   497     gint64 srcval, GstFormat dest_format, gint64 * destval)
       
   498 {
       
   499   gboolean ret = TRUE;
       
   500   guint samplesize, rate;
       
   501 
       
   502   if (dest_format == src_format) {
       
   503     *destval = srcval;
       
   504     return TRUE;
       
   505   }
       
   506 
       
   507   GST_OBJECT_LOCK (auparse);
       
   508   samplesize = auparse->sample_size;
       
   509   rate = auparse->samplerate;
       
   510   GST_OBJECT_UNLOCK (auparse);
       
   511 
       
   512   if (samplesize == 0 || rate == 0) {
       
   513     GST_LOG_OBJECT (auparse, "cannot convert, sample_size or rate unknown");
       
   514     return FALSE;
       
   515   }
       
   516 
       
   517   switch (src_format) {
       
   518     case GST_FORMAT_BYTES:
       
   519       srcval /= samplesize;
       
   520       /* fallthrough */
       
   521     case GST_FORMAT_DEFAULT:{
       
   522       switch (dest_format) {
       
   523         case GST_FORMAT_BYTES:
       
   524           *destval = srcval * samplesize;
       
   525           break;
       
   526         case GST_FORMAT_TIME:
       
   527           *destval = gst_util_uint64_scale_int (srcval, GST_SECOND, rate);
       
   528           break;
       
   529         default:
       
   530           ret = FALSE;
       
   531           break;
       
   532       }
       
   533       break;
       
   534     }
       
   535     case GST_FORMAT_TIME:{
       
   536       switch (dest_format) {
       
   537         case GST_FORMAT_BYTES:
       
   538           *destval =
       
   539               gst_util_uint64_scale_int (srcval, rate * samplesize, GST_SECOND);
       
   540           break;
       
   541         case GST_FORMAT_DEFAULT:
       
   542           *destval = gst_util_uint64_scale_int (srcval, rate, GST_SECOND);
       
   543           break;
       
   544         default:
       
   545           ret = FALSE;
       
   546           break;
       
   547       }
       
   548       break;
       
   549     }
       
   550     default:{
       
   551       ret = FALSE;
       
   552       break;
       
   553     }
       
   554   }
       
   555 
       
   556   if (!ret) {
       
   557     GST_DEBUG_OBJECT (auparse, "could not convert from %s to %s format",
       
   558         gst_format_get_name (src_format), gst_format_get_name (dest_format));
       
   559   }
       
   560 
       
   561   return ret;
       
   562 }
       
   563 
       
   564 static gboolean
       
   565 gst_au_parse_src_query (GstPad * pad, GstQuery * query)
       
   566 {
       
   567   GstAuParse *auparse;
       
   568   gboolean ret = FALSE;
       
   569 
       
   570   auparse = GST_AU_PARSE (gst_pad_get_parent (pad));
       
   571 
       
   572   switch (GST_QUERY_TYPE (query)) {
       
   573     case GST_QUERY_DURATION:{
       
   574       GstFormat bformat = GST_FORMAT_BYTES;
       
   575       GstFormat format;
       
   576       gint64 len, val;
       
   577 
       
   578       gst_query_parse_duration (query, &format, NULL);
       
   579       if (!gst_pad_query_peer_duration (auparse->sinkpad, &bformat, &len)) {
       
   580         GST_DEBUG_OBJECT (auparse, "failed to query upstream length");
       
   581         break;
       
   582       }
       
   583       GST_OBJECT_LOCK (auparse);
       
   584       len -= auparse->offset;
       
   585       GST_OBJECT_UNLOCK (auparse);
       
   586 
       
   587       ret = gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, len,
       
   588           format, &val);
       
   589 
       
   590       if (ret) {
       
   591         gst_query_set_duration (query, format, val);
       
   592       }
       
   593       break;
       
   594     }
       
   595     case GST_QUERY_POSITION:{
       
   596       GstFormat bformat = GST_FORMAT_BYTES;
       
   597       GstFormat format;
       
   598       gint64 pos, val;
       
   599 
       
   600       gst_query_parse_position (query, &format, NULL);
       
   601       if (!gst_pad_query_peer_position (auparse->sinkpad, &bformat, &pos)) {
       
   602         GST_DEBUG_OBJECT (auparse, "failed to query upstream position");
       
   603         break;
       
   604       }
       
   605       GST_OBJECT_LOCK (auparse);
       
   606       pos -= auparse->offset;
       
   607       GST_OBJECT_UNLOCK (auparse);
       
   608 
       
   609       ret = gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, pos,
       
   610           format, &val);
       
   611 
       
   612       if (ret) {
       
   613         gst_query_set_position (query, format, val);
       
   614       }
       
   615       break;
       
   616     }
       
   617     default:
       
   618       ret = gst_pad_query_default (pad, query);
       
   619       break;
       
   620   }
       
   621 
       
   622   gst_object_unref (auparse);
       
   623   return ret;
       
   624 }
       
   625 
       
   626 static gboolean
       
   627 gst_au_parse_handle_seek (GstAuParse * auparse, GstEvent * event)
       
   628 {
       
   629   GstSeekType start_type, stop_type;
       
   630   GstSeekFlags flags;
       
   631   GstFormat format;
       
   632   gdouble rate;
       
   633   gint64 start, stop;
       
   634 
       
   635   gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start,
       
   636       &stop_type, &stop);
       
   637 
       
   638   if (format != GST_FORMAT_TIME) {
       
   639     GST_DEBUG_OBJECT (auparse, "only support seeks in TIME format");
       
   640     return FALSE;
       
   641   }
       
   642 
       
   643   /* FIXME: implement seeking */
       
   644   return FALSE;
       
   645 }
       
   646 
       
   647 static gboolean
       
   648 gst_au_parse_sink_event (GstPad * pad, GstEvent * event)
       
   649 {
       
   650   GstAuParse *auparse;
       
   651   gboolean ret;
       
   652 
       
   653   auparse = GST_AU_PARSE (gst_pad_get_parent (pad));
       
   654 
       
   655   switch (GST_EVENT_TYPE (event)) {
       
   656     default:
       
   657       ret = gst_pad_event_default (pad, event);
       
   658       break;
       
   659   }
       
   660 
       
   661   gst_object_unref (auparse);
       
   662   return ret;
       
   663 }
       
   664 
       
   665 static gboolean
       
   666 gst_au_parse_src_event (GstPad * pad, GstEvent * event)
       
   667 {
       
   668   GstAuParse *auparse;
       
   669   gboolean ret;
       
   670 
       
   671   auparse = GST_AU_PARSE (gst_pad_get_parent (pad));
       
   672 
       
   673   switch (GST_EVENT_TYPE (event)) {
       
   674     case GST_EVENT_SEEK:
       
   675       ret = gst_au_parse_handle_seek (auparse, event);
       
   676       break;
       
   677     default:
       
   678       ret = gst_pad_event_default (pad, event);
       
   679       break;
       
   680   }
       
   681 
       
   682   gst_object_unref (auparse);
       
   683   return ret;
       
   684 }
       
   685 
       
   686 static GstStateChangeReturn
       
   687 gst_au_parse_change_state (GstElement * element, GstStateChange transition)
       
   688 {
       
   689   GstAuParse *auparse = GST_AU_PARSE (element);
       
   690   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
       
   691 
       
   692   ret = parent_class->change_state (element, transition);
       
   693   if (ret == GST_STATE_CHANGE_FAILURE)
       
   694     return ret;
       
   695 
       
   696   switch (transition) {
       
   697     case GST_STATE_CHANGE_PAUSED_TO_READY:
       
   698       gst_au_parse_reset (auparse);
       
   699     default:
       
   700       break;
       
   701   }
       
   702 
       
   703   return ret;
       
   704 }
       
   705 
       
   706 static gboolean
       
   707 plugin_init (GstPlugin * plugin)
       
   708 {
       
   709   if (!gst_element_register (plugin, "auparse", GST_RANK_SECONDARY,
       
   710           GST_TYPE_AU_PARSE)) {
       
   711     return FALSE;
       
   712   }
       
   713 
       
   714   return TRUE;
       
   715 }
       
   716 
       
   717 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
       
   718     GST_VERSION_MINOR,
       
   719     "auparse",
       
   720     "parses au streams", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
       
   721     GST_PACKAGE_ORIGIN)
       
   722 	
       
   723 EXPORT_C GstPluginDesc* _GST_PLUGIN_DESC()
       
   724 {
       
   725 	return &gst_plugin_desc;
       
   726 }