gstauparse.c 12.2 KB
Newer Older
1
/* GStreamer
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
19
/* Element-Checklist-Version: 5 */
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
20 21

/* 2001/04/03 - Updated parseau to use caps nego
22
 *              Zaheer Abbas Merali <zaheerabbas at merali dot org>
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
23 24
 */

25 26 27
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
28 29 30
#include <stdlib.h>
#include <string.h>

Steve Lhomme Lhomme's avatar
Steve Lhomme Lhomme committed
31
#include "gstauparse.h"
David Schleef's avatar
David Schleef committed
32
#include <gst/audio/audio.h>
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
33 34

/* elementfactory information */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
35 36
static GstElementDetails gst_auparse_details =
GST_ELEMENT_DETAILS (".au parser",
37
    "Codec/Demuxer/Audio",
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
38 39
    "Parse an .au file into raw audio",
    "Erik Walthinsen <omega@cse.ogi.edu>");
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
40

David Schleef's avatar
David Schleef committed
41
static GstStaticPadTemplate gst_auparse_sink_template =
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
42 43 44 45 46
GST_STATIC_PAD_TEMPLATE ("sink",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("audio/x-au")
    );
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
47

David Schleef's avatar
David Schleef committed
48
static GstStaticPadTemplate gst_auparse_src_template =
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
49 50
    GST_STATIC_PAD_TEMPLATE ("src",
    GST_PAD_SRC,
51
    GST_PAD_SOMETIMES,          /* FIXME: spider */
52 53
    GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS "; "       /* 24-bit PCM is barely supported by gstreamer actually */
        GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS "; "  /* 64-bit float is barely supported by gstreamer actually */
54 55 56 57 58
        "audio/x-alaw, " "rate = (int) [ 8000, 192000 ], "
        "channels = (int) [ 1, 2 ]" "; " "audio/x-mulaw, "
        "rate = (int) [ 8000, 192000 ], " "channels = (int) [ 1, 2 ]" "; "
        /* Nothing to decode those ADPCM streams for now */
        "audio/x-adpcm, " "layout = (string) { g721, g722, g723_3, g723_5 }")
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
59
    );
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
60

61
/* AuParse signals and args */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
62 63
enum
{
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
64 65 66 67
  /* FILL ME */
  LAST_SIGNAL
};

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
68 69
enum
{
70 71
  ARG_0
      /* FILL ME */
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
72 73
};

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
74 75 76
static void gst_auparse_base_init (gpointer g_class);
static void gst_auparse_class_init (GstAuParseClass * klass);
static void gst_auparse_init (GstAuParse * auparse);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
77

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
78
static void gst_auparse_chain (GstPad * pad, GstData * _data);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
79

80 81
static GstElementStateReturn gst_auparse_change_state (GstElement * element);

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
82
static GstElementClass *parent_class = NULL;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
83

84
/*static guint gst_auparse_signals[LAST_SIGNAL] = { 0 }; */
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
85 86

GType
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
87
gst_auparse_get_type (void)
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
88
{
89
  static GType auparse_type = 0;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
90

91 92
  if (!auparse_type) {
    static const GTypeInfo auparse_info = {
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
93
      sizeof (GstAuParseClass),
94
      gst_auparse_base_init,
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
95
      NULL,
96
      (GClassInitFunc) gst_auparse_class_init,
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
97 98
      NULL,
      NULL,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
99
      sizeof (GstAuParse),
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
100
      0,
101
      (GInstanceInitFunc) gst_auparse_init,
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
102
    };
103

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
104
    auparse_type =
105 106
        g_type_register_static (GST_TYPE_ELEMENT, "GstAuParse", &auparse_info,
        0);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
107
  }
108
  return auparse_type;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
109 110
}

111 112 113 114 115 116
static void
gst_auparse_base_init (gpointer g_class)
{
  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);

  gst_element_class_add_pad_template (element_class,
David Schleef's avatar
David Schleef committed
117
      gst_static_pad_template_get (&gst_auparse_sink_template));
118
  gst_element_class_add_pad_template (element_class,
David Schleef's avatar
David Schleef committed
119
      gst_static_pad_template_get (&gst_auparse_src_template));
120 121 122 123
  gst_element_class_set_details (element_class, &gst_auparse_details);

}

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
124
static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
125
gst_auparse_class_init (GstAuParseClass * klass)
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
126 127 128
{
  GstElementClass *gstelement_class;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
129
  gstelement_class = (GstElementClass *) klass;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
130 131

  parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
132 133

  gstelement_class->change_state = gst_auparse_change_state;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
134 135
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
136 137
static void
gst_auparse_init (GstAuParse * auparse)
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
138
{
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
139 140 141
  auparse->sinkpad =
      gst_pad_new_from_template (gst_static_pad_template_get
      (&gst_auparse_sink_template), "sink");
142 143
  gst_element_add_pad (GST_ELEMENT (auparse), auparse->sinkpad);
  gst_pad_set_chain_function (auparse->sinkpad, gst_auparse_chain);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
144

145 146 147
  auparse->srcpad = NULL;
#if 0                           /* FIXME: spider */
  gst_pad_new_from_template (gst_static_pad_template_get
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
148
      (&gst_auparse_src_template), "src");
149
  gst_element_add_pad (GST_ELEMENT (auparse), auparse->srcpad);
150
  gst_pad_use_explicit_caps (auparse->srcpad);
151
#endif
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
152

153 154 155 156 157
  auparse->offset = 0;
  auparse->size = 0;
  auparse->encoding = 0;
  auparse->frequency = 0;
  auparse->channels = 0;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
158 159
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
160 161
static void
gst_auparse_chain (GstPad * pad, GstData * _data)
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
162
{
163
  GstBuffer *buf = GST_BUFFER (_data);
164
  GstAuParse *auparse;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
165 166
  gchar *data;
  glong size;
David Schleef's avatar
David Schleef committed
167
  GstCaps *tempcaps;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
168
  gint law = 0, depth = 0, ieee = 0;
169 170 171
  gchar layout[7];

  layout[0] = 0;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
172 173 174 175 176

  g_return_if_fail (pad != NULL);
  g_return_if_fail (GST_IS_PAD (pad));
  g_return_if_fail (buf != NULL);

177
  auparse = GST_AUPARSE (gst_pad_get_parent (pad));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
178

179
  GST_DEBUG ("gst_auparse_chain: got buffer in '%s'",
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
180
      gst_element_get_name (GST_ELEMENT (auparse)));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
181 182 183 184 185

  data = GST_BUFFER_DATA (buf);
  size = GST_BUFFER_SIZE (buf);

  /* if we haven't seen any data yet... */
186
  if (auparse->size == 0) {
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
187
    GstBuffer *newbuf;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
188
    guint32 *head = (guint32 *) data;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
189 190

    /* normal format is big endian (au is a Sparc format) */
191
    if (GST_READ_UINT32_BE (head) == 0x2e736e64) {      /* ".snd" */
192
      head++;
193
      auparse->le = 0;
194
      auparse->offset = GST_READ_UINT32_BE (head);
195
      head++;
196 197
      /* Do not trust size, could be set to -1 : unknown */
      auparse->size = GST_READ_UINT32_BE (head);
198
      head++;
199
      auparse->encoding = GST_READ_UINT32_BE (head);
200
      head++;
201
      auparse->frequency = GST_READ_UINT32_BE (head);
202
      head++;
203
      auparse->channels = GST_READ_UINT32_BE (head);
204
      head++;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
205

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
206 207
      /* and of course, someone had to invent a little endian
       * version.  Used by DEC systems. */
208
    } else if (GST_READ_UINT32_LE (head) == 0x0064732E) {       /* other source say it is "dns." */
209
      head++;
210
      auparse->le = 1;
211
      auparse->offset = GST_READ_UINT32_LE (head);
212
      head++;
213 214
      /* Do not trust size, could be set to -1 : unknown */
      auparse->size = GST_READ_UINT32_LE (head);
215
      head++;
216
      auparse->encoding = GST_READ_UINT32_LE (head);
217
      head++;
218
      auparse->frequency = GST_READ_UINT32_LE (head);
219
      head++;
220
      auparse->channels = GST_READ_UINT32_LE (head);
221
      head++;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
222 223

    } else {
224
      GST_ELEMENT_ERROR (auparse, STREAM, WRONG_TYPE, (NULL), (NULL));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
225
      gst_buffer_unref (buf);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
226 227 228
      return;
    }

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
229
    GST_DEBUG
230 231 232
        ("offset %ld, size %ld, encoding %ld, frequency %ld, channels %ld",
        auparse->offset, auparse->size, auparse->encoding, auparse->frequency,
        auparse->channels);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
233

234 235 236 237
/*
Docs :
	http://www.opengroup.org/public/pubs/external/auformat.html
	http://astronomy.swin.edu.au/~pbourke/dataformats/au/
238 239
	Solaris headers : /usr/include/audio/au.h
	libsndfile : src/au.c
240 241 242 243
Samples :
	http://www.tsp.ece.mcgill.ca/MMSP/Documents/AudioFormats/AU/Samples.html
*/

244
    switch (auparse->encoding) {
245

246
      case 1:                  /* 8-bit ISDN mu-law G.711 */
247 248 249
        law = 1;
        depth = 8;
        break;
250 251 252 253
      case 27:                 /* 8-bit ISDN  A-law G.711 */
        law = 2;
        depth = 8;
        break;
254

255
      case 2:                  /*  8-bit linear PCM */
256 257
        depth = 8;
        break;
258
      case 3:                  /* 16-bit linear PCM */
259 260
        depth = 16;
        break;
261 262 263 264 265 266 267
      case 4:                  /* 24-bit linear PCM */
        depth = 24;
        break;
      case 5:                  /* 32-bit linear PCM */
        depth = 32;
        break;

268
      case 6:                  /* 32-bit IEEE floating point */
269 270 271
        ieee = 1;
        depth = 32;
        break;
272
      case 7:                  /* 64-bit IEEE floating point */
273 274 275 276
        ieee = 1;
        depth = 64;
        break;

277 278 279 280 281 282 283 284 285 286 287 288 289
      case 23:                 /* 4-bit CCITT G.721   ADPCM 32kbps -> modplug/libsndfile (compressed 8-bit mu-law) */
        strcpy (layout, "g721");
        break;
      case 24:                 /* 8-bit CCITT G.722   ADPCM        -> rtp */
        strcpy (layout, "g722");
        break;
      case 25:                 /* 3-bit CCITT G.723.3 ADPCM 24kbps -> rtp/xine/modplug/libsndfile */
        strcpy (layout, "g723_3");
        break;
      case 26:                 /* 5-bit CCITT G.723.5 ADPCM 40kbps -> rtp/xine/modplug/libsndfile */
        strcpy (layout, "g723_5");
        break;

290 291 292 293 294 295 296 297 298 299 300 301 302
      case 8:                  /* Fragmented sample data */
      case 9:                  /* AU_ENCODING_NESTED */

      case 10:                 /* DSP program */
      case 11:                 /* DSP  8-bit fixed point */
      case 12:                 /* DSP 16-bit fixed point */
      case 13:                 /* DSP 24-bit fixed point */
      case 14:                 /* DSP 32-bit fixed point */

      case 16:                 /* AU_ENCODING_DISPLAY : non-audio display data */
      case 17:                 /* AU_ENCODING_MULAW_SQUELCH */

      case 18:                 /* 16-bit linear with emphasis */
303
      case 19:                 /* 16-bit linear compressed (NeXT) */
304 305 306 307 308
      case 20:                 /* 16-bit linear with emphasis and compression */

      case 21:                 /* Music kit DSP commands */
      case 22:                 /* Music kit DSP commands samples */

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
309
      default:
310 311
        GST_ELEMENT_ERROR (auparse, STREAM, FORMAT, (NULL), (NULL));
        gst_buffer_unref (buf);
312
        return;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
313 314
    }

315 316 317 318 319
    auparse->srcpad =
        gst_pad_new_from_template (gst_static_pad_template_get
        (&gst_auparse_src_template), "src");
    gst_pad_use_explicit_caps (auparse->srcpad);

320
    if (law) {
321 322 323 324 325 326 327 328 329
      tempcaps =
          gst_caps_new_simple ((law == 1) ? "audio/x-mulaw" : "audio/x-alaw",
          "rate", G_TYPE_INT, auparse->frequency, "channels", G_TYPE_INT,
          auparse->channels, NULL);
    } else if (ieee) {
      tempcaps = gst_caps_new_simple ("audio/x-raw-float",
          "width", G_TYPE_INT, depth,
          "endianness", G_TYPE_INT,
          auparse->le ? G_LITTLE_ENDIAN : G_BIG_ENDIAN, NULL);
330
    } else if (layout[0]) {
331 332
      tempcaps = gst_caps_new_simple ("audio/x-adpcm",
          "layout", G_TYPE_STRING, layout, NULL);
333
    } else {
David Schleef's avatar
David Schleef committed
334
      tempcaps = gst_caps_new_simple ("audio/x-raw-int",
335 336 337 338 339
          "endianness", G_TYPE_INT,
          auparse->le ? G_LITTLE_ENDIAN : G_BIG_ENDIAN, "rate", G_TYPE_INT,
          auparse->frequency, "channels", G_TYPE_INT, auparse->channels,
          "depth", G_TYPE_INT, depth, "width", G_TYPE_INT, depth, "signed",
          G_TYPE_BOOLEAN, TRUE, NULL);
340
    }
341

342
    if (!gst_pad_set_explicit_caps (auparse->srcpad, tempcaps)) {
343
      GST_ELEMENT_ERROR (auparse, CORE, NEGOTIATION, (NULL), (NULL));
344
      gst_buffer_unref (buf);
345 346
      gst_object_unref (GST_OBJECT (auparse->srcpad));
      auparse->srcpad = NULL;
347 348
      return;
    }
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
349

350 351
    gst_element_add_pad (GST_ELEMENT (auparse), auparse->srcpad);

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
352
    newbuf = gst_buffer_new ();
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
353
    GST_BUFFER_DATA (newbuf) = (gpointer) malloc (size - (auparse->offset));
354 355
    memcpy (GST_BUFFER_DATA (newbuf), data + (auparse->offset),
        size - (auparse->offset));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
356
    GST_BUFFER_SIZE (newbuf) = size - (auparse->offset);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
357 358 359

    gst_buffer_unref (buf);

360
    gst_pad_push (auparse->srcpad, GST_DATA (newbuf));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
361 362 363
    return;
  }

364
  gst_pad_push (auparse->srcpad, GST_DATA (buf));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
365 366
}

367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
static GstElementStateReturn
gst_auparse_change_state (GstElement * element)
{
  GstAuParse *auparse = GST_AUPARSE (element);

  switch (GST_STATE_TRANSITION (element)) {
    case GST_STATE_PAUSED_TO_READY:
      if (auparse->srcpad) {
        gst_element_remove_pad (element, auparse->srcpad);
        auparse->srcpad = NULL;
      }
      break;
    default:
      break;
  }

  if (parent_class->change_state)
    return parent_class->change_state (element);

  return GST_STATE_SUCCESS;
}
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
388 389

static gboolean
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
390
plugin_init (GstPlugin * plugin)
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
391
{
392
  if (!gst_element_register (plugin, "auparse", GST_RANK_SECONDARY,
393
          GST_TYPE_AUPARSE)) {
394 395
    return FALSE;
  }
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
396 397 398 399

  return TRUE;
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
400 401 402
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
    GST_VERSION_MINOR,
    "auparse",
403
    "parses au streams", plugin_init, VERSION, "LGPL", GST_PACKAGE, GST_ORIGIN)