gstauparse.c 21 KB
Newer Older
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
1
/* GStreamer
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
2
 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3
 * Copyright (C) <2006> Tim-Philipp Müller <tim centricular net>
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 *
 * 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.
 */

21
22
23
24
25
26
27
28
29
/**
 * SECTION:element-auparse
 * @short_description: .au file parser
 * 
 * <refsect2>
 * <para>
 * Parses .au files.
 * </para>
 * </refsect2>
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
30
31
 */

32
33
34
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
35

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
36
37
38
#include <stdlib.h>
#include <string.h>

Steve Lhomme Lhomme's avatar
Steve Lhomme Lhomme committed
39
#include "gstauparse.h"
David Schleef's avatar
David Schleef committed
40
#include <gst/audio/audio.h>
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
41

42
43
44
GST_DEBUG_CATEGORY_STATIC (auparse_debug);
#define GST_CAT_DEFAULT (auparse_debug)

45
static const GstElementDetails gst_au_parse_details =
Wim Taymans's avatar
Wim Taymans committed
46
GST_ELEMENT_DETAILS ("AU audio demuxer",
47
    "Codec/Demuxer/Audio",
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
48
49
    "Parse an .au file into raw audio",
    "Erik Walthinsen <omega@cse.ogi.edu>");
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
50

51
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
52
53
54
55
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("audio/x-au")
    );
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
56

57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#define GST_AU_PARSE_ALAW_PAD_TEMPLATE_CAPS \
    "audio/x-alaw, "                        \
    "rate = (int) [ 8000, 192000 ], "       \
    "channels = (int) [ 1, 2 ]"

#define GST_AU_PARSE_MULAW_PAD_TEMPLATE_CAPS \
    "audio/x-mulaw, "                        \
    "rate = (int) [ 8000, 192000 ], "        \
    "channels = (int) [ 1, 2 ]"

/* Nothing to decode those ADPCM streams for now */
#define GST_AU_PARSE_ADPCM_PAD_TEMPLATE_CAPS \
    "audio/x-adpcm, "                        \
    "layout = (string) { g721, g722, g723_3, g723_5 }"

72
static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
73
    GST_PAD_SRC,
74
    GST_PAD_SOMETIMES,
75
    GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS "; "
76
77
78
79
        GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS ";"
        GST_AU_PARSE_ALAW_PAD_TEMPLATE_CAPS ";"
        GST_AU_PARSE_MULAW_PAD_TEMPLATE_CAPS ";"
        GST_AU_PARSE_ADPCM_PAD_TEMPLATE_CAPS));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
80
81


82
83
84
static void gst_au_parse_dispose (GObject * object);
static GstFlowReturn gst_au_parse_chain (GstPad * pad, GstBuffer * buf);
static GstStateChangeReturn gst_au_parse_change_state (GstElement * element,
85
    GstStateChange transition);
86
87
88
89
90
91
static void gst_au_parse_reset (GstAuParse * auparse);
static gboolean gst_au_parse_remove_srcpad (GstAuParse * auparse);
static gboolean gst_au_parse_add_srcpad (GstAuParse * auparse, GstCaps * caps);
static gboolean gst_au_parse_src_query (GstPad * pad, GstQuery * query);
static gboolean gst_au_parse_src_event (GstPad * pad, GstEvent * event);
static gboolean gst_au_parse_sink_event (GstPad * pad, GstEvent * event);
92

93
GST_BOILERPLATE (GstAuParse, gst_au_parse, GstElement, GST_TYPE_ELEMENT);
94

95
96
static void
gst_au_parse_base_init (gpointer g_class)
97
98
99
100
{
  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);

  gst_element_class_add_pad_template (element_class,
101
      gst_static_pad_template_get (&sink_template));
102
  gst_element_class_add_pad_template (element_class,
103
      gst_static_pad_template_get (&src_template));
104
  gst_element_class_set_details (element_class, &gst_au_parse_details);
105

106
  GST_DEBUG_CATEGORY_INIT (auparse_debug, "auparse", 0, ".au parser");
107
108
}

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
109
static void
110
gst_au_parse_class_init (GstAuParseClass * klass)
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
111
{
112
  GObjectClass *gobject_class;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
113
114
  GstElementClass *gstelement_class;

115
  gobject_class = (GObjectClass *) klass;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
116
  gstelement_class = (GstElementClass *) klass;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
117

118
  gobject_class->dispose = gst_au_parse_dispose;
119

120
121
  gstelement_class->change_state =
      GST_DEBUG_FUNCPTR (gst_au_parse_change_state);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
122
123
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
124
static void
125
gst_au_parse_init (GstAuParse * auparse, GstAuParseClass * klass)
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
126
{
127
128
129
130
131
  auparse->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
  gst_pad_set_chain_function (auparse->sinkpad,
      GST_DEBUG_FUNCPTR (gst_au_parse_chain));
  gst_pad_set_event_function (auparse->sinkpad,
      GST_DEBUG_FUNCPTR (gst_au_parse_sink_event));
Wim Taymans's avatar
Wim Taymans committed
132
  gst_element_add_pad (GST_ELEMENT (auparse), auparse->sinkpad);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
133

134
  auparse->srcpad = NULL;
135
  auparse->adapter = gst_adapter_new ();
136
  gst_au_parse_reset (auparse);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
137
138
}

139
static void
140
gst_au_parse_dispose (GObject * object)
141
{
142
  GstAuParse *au = GST_AU_PARSE (object);
143
144

  if (au->adapter != NULL) {
145
    g_object_unref (au->adapter);
146
147
148
149
150
    au->adapter = NULL;
  }
  G_OBJECT_CLASS (parent_class)->dispose (object);
}

151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
static void
gst_au_parse_reset (GstAuParse * auparse)
{
  gst_au_parse_remove_srcpad (auparse);

  auparse->offset = 0;
  auparse->buffer_offset = 0;
  auparse->encoding = 0;
  auparse->samplerate = 0;
  auparse->channels = 0;
  auparse->float_swap = 0;

  gst_adapter_clear (auparse->adapter);

  /* gst_segment_init (&auparse->segment, GST_FORMAT_TIME); */
}

static gboolean
gst_au_parse_add_srcpad (GstAuParse * auparse, GstCaps * new_caps)
{
  GstPad *srcpad = NULL;

  if (auparse->src_caps && gst_caps_is_equal (new_caps, auparse->src_caps)) {
    GST_LOG_OBJECT (auparse, "same caps, nothing to do");
    return TRUE;
  }

  gst_caps_replace (&auparse->src_caps, new_caps);
  if (auparse->srcpad != NULL) {
    GST_DEBUG_OBJECT (auparse, "Changing src pad caps to %" GST_PTR_FORMAT,
        auparse->src_caps);
    gst_pad_set_caps (auparse->srcpad, auparse->src_caps);
  }

  if (auparse->srcpad == NULL) {
    srcpad = auparse->srcpad =
        gst_pad_new_from_static_template (&src_template, "src");
    g_return_val_if_fail (auparse->srcpad != NULL, FALSE);

#if 0
    gst_pad_set_query_type_function (auparse->srcpad,
        GST_DEBUG_FUNCPTR (gst_au_parse_src_get_query_types));
#endif
    gst_pad_set_query_function (auparse->srcpad,
        GST_DEBUG_FUNCPTR (gst_au_parse_src_query));
    gst_pad_set_event_function (auparse->srcpad,
        GST_DEBUG_FUNCPTR (gst_au_parse_src_event));

    gst_pad_use_fixed_caps (auparse->srcpad);
Wim Taymans's avatar
Wim Taymans committed
200
    gst_pad_set_active (auparse->srcpad, TRUE);
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232

    if (auparse->src_caps)
      gst_pad_set_caps (auparse->srcpad, auparse->src_caps);

    GST_DEBUG_OBJECT (auparse, "Adding src pad with caps %" GST_PTR_FORMAT,
        auparse->src_caps);

    gst_object_ref (auparse->srcpad);
    if (!gst_element_add_pad (GST_ELEMENT (auparse), auparse->srcpad))
      return FALSE;
    gst_element_no_more_pads (GST_ELEMENT (auparse));
  }

  return TRUE;
}

static gboolean
gst_au_parse_remove_srcpad (GstAuParse * auparse)
{
  gboolean res = TRUE;

  if (auparse->srcpad != NULL) {
    GST_DEBUG_OBJECT (auparse, "Removing src pad");
    res = gst_element_remove_pad (GST_ELEMENT (auparse), auparse->srcpad);
    g_return_val_if_fail (res != FALSE, FALSE);
    gst_object_unref (auparse->srcpad);
    auparse->srcpad = NULL;
  }

  return res;
}

233
static GstFlowReturn
234
gst_au_parse_parse_header (GstAuParse * auparse)
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
235
{
David Schleef's avatar
David Schleef committed
236
  GstCaps *tempcaps;
237
238
239
  guint32 size;
  guint8 *head;
  gchar layout[7] = { 0, };
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
240
  gint law = 0, depth = 0, ieee = 0;
241

242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
  head = (guint8 *) gst_adapter_peek (auparse->adapter, 24);
  g_assert (head != NULL);

  GST_DEBUG_OBJECT (auparse, "[%c%c%c%c]", head[0], head[1], head[2], head[3]);

  switch (GST_READ_UINT32_BE (head)) {
      /* normal format is big endian (au is a Sparc format) */
    case 0x2e736e64:{          /* ".snd" */
      auparse->endianness = G_BIG_ENDIAN;
      break;
    }
      /* and of course, someone had to invent a little endian
       * version.  Used by DEC systems. */
    case 0x646e732e:           /* dns.                          */
    case 0x0064732e:{          /* other source say it is "dns." */
      auparse->endianness = G_LITTLE_ENDIAN;
      break;
    }
    default:{
      goto unknown_header;
    }
  }

  auparse->offset = GST_READ_UINT32_BE (head + 4);
  /* Do not trust size, could be set to -1 : unknown */
  size = GST_READ_UINT32_BE (head + 8);
  auparse->encoding = GST_READ_UINT32_BE (head + 12);
  auparse->samplerate = GST_READ_UINT32_BE (head + 16);
  auparse->channels = GST_READ_UINT32_BE (head + 20);

Tim-Philipp Müller's avatar
Tim-Philipp Müller committed
272
273
  GST_DEBUG_OBJECT (auparse, "offset %" G_GINT64_FORMAT ", size %u, "
      "encoding %u, frequency %u, channels %u", auparse->offset, size,
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
      auparse->encoding, auparse->samplerate, auparse->channels);

  /* Docs:
   * http://www.opengroup.org/public/pubs/external/auformat.html
   * http://astronomy.swin.edu.au/~pbourke/dataformats/au/
   * Solaris headers : /usr/include/audio/au.h
   * libsndfile : src/au.c
   *
   * Samples :
   * http://www.tsp.ece.mcgill.ca/MMSP/Documents/AudioFormats/AU/Samples.html
   */

  auparse->float_swap = 0;

  switch (auparse->encoding) {
    case 1:                    /* 8-bit ISDN mu-law G.711 */
      law = 1;
      depth = 8;
      break;
    case 27:                   /* 8-bit ISDN  A-law G.711 */
      law = 2;
      depth = 8;
      break;

    case 2:                    /*  8-bit linear PCM */
      depth = 8;
      break;
    case 3:                    /* 16-bit linear PCM */
      depth = 16;
      break;
    case 4:                    /* 24-bit linear PCM */
      depth = 24;
      break;
    case 5:                    /* 32-bit linear PCM */
      depth = 32;
      break;

    case 6:                    /* 32-bit IEEE floating point */
      ieee = 1;
      depth = 32;
      break;
    case 7:                    /* 64-bit IEEE floating point */
      ieee = 1;
      depth = 64;
      break;

    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;

    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 */
    case 19:                   /* 16-bit linear compressed (NeXT) */
    case 20:                   /* 16-bit linear with emphasis and compression */

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

    default:
      goto unknown_format;
  }

  if (law) {
    tempcaps =
        gst_caps_new_simple ((law == 1) ? "audio/x-mulaw" : "audio/x-alaw",
        "rate", G_TYPE_INT, auparse->samplerate,
        "channels", G_TYPE_INT, auparse->channels, NULL);
    auparse->sample_size = auparse->channels;
  } else if (ieee) {
    tempcaps = gst_caps_new_simple ("audio/x-raw-float",
        "rate", G_TYPE_INT, auparse->samplerate,
        "channels", G_TYPE_INT, auparse->channels,
        "endianness", G_TYPE_INT, G_BYTE_ORDER,
        "width", G_TYPE_INT, depth, NULL);
    auparse->sample_size = auparse->channels * depth / 8;
    if (auparse->endianness != G_BYTE_ORDER) {
      GST_DEBUG_OBJECT (auparse, "need to swap float byte order ourselves!");
      auparse->float_swap = depth;
    }
  } else if (layout[0]) {
    tempcaps = gst_caps_new_simple ("audio/x-adpcm",
        "layout", G_TYPE_STRING, layout, NULL);
    auparse->sample_size = 0;
  } else {
    tempcaps = gst_caps_new_simple ("audio/x-raw-int",
        "rate", G_TYPE_INT, auparse->samplerate,
        "channels", G_TYPE_INT, auparse->channels,
        "endianness", G_TYPE_INT, auparse->endianness,
        "depth", G_TYPE_INT, depth, "width", G_TYPE_INT, depth,
        /* FIXME: signed TRUE even for 8-bit PCM? */
        "signed", G_TYPE_BOOLEAN, TRUE, NULL);
    auparse->sample_size = auparse->channels * depth / 8;
  }

  GST_DEBUG_OBJECT (auparse, "sample_size=%d", auparse->sample_size);

  if (!gst_au_parse_add_srcpad (auparse, tempcaps))
    goto add_pad_failed;

Tim-Philipp Müller's avatar
Tim-Philipp Müller committed
393
  GST_DEBUG_OBJECT (auparse, "offset=%" G_GINT64_FORMAT, auparse->offset);
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
  gst_adapter_flush (auparse->adapter, auparse->offset);

  gst_caps_unref (tempcaps);
  return GST_FLOW_OK;

  /* ERRORS */
unknown_header:
  {
    GST_ELEMENT_ERROR (auparse, STREAM, WRONG_TYPE, (NULL), (NULL));
    return GST_FLOW_ERROR;
  }
unknown_format:
  {
    GST_ELEMENT_ERROR (auparse, STREAM, FORMAT, (NULL), (NULL));
    return GST_FLOW_ERROR;
  }
add_pad_failed:
  {
    GST_ELEMENT_ERROR (auparse, STREAM, FAILED, (NULL),
        ("Failed to add srcpad"));
    gst_caps_unref (tempcaps);
    return GST_FLOW_ERROR;
  }
}

#define AU_HEADER_SIZE 24

static GstFlowReturn
gst_au_parse_chain (GstPad * pad, GstBuffer * buf)
{
  GstFlowReturn ret = GST_FLOW_OK;
  GstAuParse *auparse;
  gint avail, sendnow = 0;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
427

428
  auparse = GST_AU_PARSE (gst_pad_get_parent (pad));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
429

430
  GST_LOG_OBJECT (auparse, "got buffer of size %u", GST_BUFFER_SIZE (buf));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
431

432
433
  gst_adapter_push (auparse->adapter, buf);
  buf = NULL;
434

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
435
  /* if we haven't seen any data yet... */
436
437
438
439
440
441
  if (auparse->srcpad == NULL) {
    if (gst_adapter_available (auparse->adapter) < AU_HEADER_SIZE) {
      GST_DEBUG_OBJECT (auparse, "need more data to parse header");
      ret = GST_FLOW_OK;
      goto out;
    }
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
442

443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
    ret = gst_au_parse_parse_header (auparse);
    if (ret != GST_FLOW_OK)
      goto out;

    gst_pad_push_event (auparse->srcpad,
        gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_DEFAULT,
            0, GST_CLOCK_TIME_NONE, 0));
  }

  avail = gst_adapter_available (auparse->adapter);

  if (auparse->sample_size > 0) {
    /* Ensure we push a buffer that's a multiple of the frame size downstream */
    sendnow = avail - (avail % auparse->sample_size);
  } else {
    /* It's something non-trivial (such as ADPCM), we don't understand it, so
     * just push downstream and assume it will know what to do with it */
    sendnow = avail;
  }

  if (sendnow > 0) {
    GstBuffer *outbuf;
    const guint8 *data;

    ret = gst_pad_alloc_buffer_and_set_caps (auparse->srcpad,
        auparse->buffer_offset, sendnow, GST_PAD_CAPS (auparse->srcpad),
        &outbuf);

    if (ret != GST_FLOW_OK) {
      GST_DEBUG_OBJECT (auparse, "pad alloc flow: %s", gst_flow_get_name (ret));
      goto out;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
474
475
    }

476
    data = gst_adapter_peek (auparse->adapter, sendnow);
477

478
479
480
481
482
483
484
485
486
487
    /* audioconvert only handles floats in native endianness ... */
    switch (auparse->float_swap) {
      case 32:{
        guint32 *indata = (guint32 *) data;
        guint32 *outdata = (guint32 *) GST_BUFFER_DATA (outbuf);
        gint i;

        for (i = 0; i < (sendnow / sizeof (guint32)); ++i) {
          outdata[i] = GUINT32_SWAP_LE_BE (indata[i]);
        }
488
        break;
489
490
491
492
493
494
495
496
497
      }
      case 64:{
        guint64 *indata = (guint64 *) data;
        guint64 *outdata = (guint64 *) GST_BUFFER_DATA (outbuf);
        gint i;

        for (i = 0; i < (sendnow / sizeof (guint64)); ++i) {
          outdata[i] = GUINT64_SWAP_LE_BE (indata[i]);
        }
498
        break;
499
500
501
      }
      default:{
        memcpy (GST_BUFFER_DATA (outbuf), data, sendnow);
502
        break;
503
504
      }
    }
505

506
    gst_adapter_flush (auparse->adapter, sendnow);
507

508
    auparse->buffer_offset += sendnow;
509

510
511
    ret = gst_pad_push (auparse->srcpad, outbuf);
  }
512

513
out:
514

515
516
517
  gst_object_unref (auparse);
  return ret;
}
518

519
520
521
522
523
524
525
static gboolean
gst_au_parse_src_convert (GstAuParse * auparse, GstFormat src_format,
    gint64 srcval, GstFormat dest_format, gint64 * destval)
{
  gboolean ret = TRUE;
  gint64 offset;
  guint samplesize, rate;
526

527
528
529
530
  if (dest_format == src_format) {
    *destval = srcval;
    return TRUE;
  }
531

532
533
534
535
536
537
538
539
540
541
  GST_OBJECT_LOCK (auparse);
  samplesize = auparse->sample_size;
  offset = auparse->offset;
  rate = auparse->samplerate;
  GST_OBJECT_UNLOCK (auparse);

  if (samplesize == 0 || rate == 0) {
    GST_LOG_OBJECT (auparse, "cannot convert, sample_size or rate unknown");
    return FALSE;
  }
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
542

543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
  switch (src_format) {
    case GST_FORMAT_BYTES:
      srcval /= samplesize;
      /* fallthrough */
    case GST_FORMAT_DEFAULT:{
      switch (dest_format) {
        case GST_FORMAT_BYTES:
          *destval = srcval * samplesize;
          break;
        case GST_FORMAT_TIME:
          *destval = gst_util_uint64_scale_int (srcval, GST_SECOND, rate);
          break;
        default:
          ret = FALSE;
          break;
      }
      break;
    }
    case GST_FORMAT_TIME:{
      switch (dest_format) {
        case GST_FORMAT_BYTES:
          *destval =
              gst_util_uint64_scale_int (srcval, rate * samplesize, GST_SECOND);
          break;
        case GST_FORMAT_DEFAULT:
          *destval = gst_util_uint64_scale_int (srcval, rate, GST_SECOND);
          break;
        default:
          ret = FALSE;
          break;
      }
      break;
    }
    default:{
      ret = FALSE;
      break;
579
    }
580
  }
581

582
583
584
585
  if (!ret) {
    GST_DEBUG_OBJECT (auparse, "could not convert from %s to %s format",
        gst_format_get_name (src_format), gst_format_get_name (dest_format));
  }
586

587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
  return ret;
}

static gboolean
gst_au_parse_src_query (GstPad * pad, GstQuery * query)
{
  GstAuParse *auparse;
  gboolean ret = FALSE;

  auparse = GST_AU_PARSE (gst_pad_get_parent (pad));

  switch (GST_QUERY_TYPE (query)) {
    case GST_QUERY_DURATION:{
      GstFormat bformat = GST_FORMAT_BYTES;
      GstFormat format;
      gint64 len, val;

      gst_query_parse_duration (query, &format, NULL);
      if (!gst_pad_query_peer_duration (auparse->sinkpad, &bformat, &len)) {
        GST_DEBUG_OBJECT (auparse, "failed to query upstream length");
        break;
      }
      GST_OBJECT_LOCK (auparse);
      len -= auparse->offset;
      GST_OBJECT_UNLOCK (auparse);
Wim Taymans's avatar
Wim Taymans committed
612

613
614
      ret = gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, len,
          format, &val);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
615

616
617
618
619
      if (ret) {
        gst_query_set_duration (query, format, val);
      }
      break;
Wim Taymans's avatar
Wim Taymans committed
620
    }
621
622
623
624
625
626
627
628
629
630
631
632
633
    case GST_QUERY_POSITION:{
      GstFormat bformat = GST_FORMAT_BYTES;
      GstFormat format;
      gint64 pos, val;

      gst_query_parse_position (query, &format, NULL);
      if (!gst_pad_query_peer_position (auparse->sinkpad, &bformat, &pos)) {
        GST_DEBUG_OBJECT (auparse, "failed to query upstream position");
        break;
      }
      GST_OBJECT_LOCK (auparse);
      pos -= auparse->offset;
      GST_OBJECT_UNLOCK (auparse);
634

635
636
      ret = gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, pos,
          format, &val);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
637

638
639
640
641
642
643
644
645
      if (ret) {
        gst_query_set_position (query, format, val);
      }
      break;
    }
    default:
      ret = gst_pad_query_default (pad, query);
      break;
646
  }
647

648
649
650
  gst_object_unref (auparse);
  return ret;
}
651

652
653
654
655
656
657
658
659
static gboolean
gst_au_parse_handle_seek (GstAuParse * auparse, GstEvent * event)
{
  GstSeekType start_type, stop_type;
  GstSeekFlags flags;
  GstFormat format;
  gdouble rate;
  gint64 start, stop;
660

661
662
  gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start,
      &stop_type, &stop);
663

664
665
666
667
  if (format != GST_FORMAT_TIME) {
    GST_DEBUG_OBJECT (auparse, "only support seeks in TIME format");
    return FALSE;
  }
668

669
670
671
  /* FIXME: implement seeking */
  return FALSE;
}
672

673
674
675
676
677
static gboolean
gst_au_parse_sink_event (GstPad * pad, GstEvent * event)
{
  GstAuParse *auparse;
  gboolean ret;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
678

679
  auparse = GST_AU_PARSE (gst_pad_get_parent (pad));
680

681
682
683
684
  switch (GST_EVENT_TYPE (event)) {
    default:
      ret = gst_pad_event_default (pad, event);
      break;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
685
686
  }

687
  gst_object_unref (auparse);
688
  return ret;
689
}
Wim Taymans's avatar
Wim Taymans committed
690

691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
static gboolean
gst_au_parse_src_event (GstPad * pad, GstEvent * event)
{
  GstAuParse *auparse;
  gboolean ret;

  auparse = GST_AU_PARSE (gst_pad_get_parent (pad));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_SEEK:
      ret = gst_au_parse_handle_seek (auparse, event);
      break;
    default:
      ret = gst_pad_event_default (pad, event);
      break;
Wim Taymans's avatar
Wim Taymans committed
706
  }
707
708
709

  gst_object_unref (auparse);
  return ret;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
710
711
}

712
static GstStateChangeReturn
713
gst_au_parse_change_state (GstElement * element, GstStateChange transition)
714
{
715
  GstAuParse *auparse = GST_AU_PARSE (element);
Edgard Gusmão Lima's avatar
Edgard Gusmão Lima committed
716
717
  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;

718
719
720
  ret = parent_class->change_state (element, transition);
  if (ret == GST_STATE_CHANGE_FAILURE)
    return ret;
Edgard Gusmão Lima's avatar
Edgard Gusmão Lima committed
721
722

  switch (transition) {
723
724
    case GST_STATE_CHANGE_PAUSED_TO_READY:
      gst_au_parse_reset (auparse);
Edgard Gusmão Lima's avatar
Edgard Gusmão Lima committed
725
726
727
    default:
      break;
  }
728

Edgard Gusmão Lima's avatar
Edgard Gusmão Lima committed
729
  return ret;
730
}
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
731
732

static gboolean
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
733
plugin_init (GstPlugin * plugin)
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
734
{
735
  if (!gst_element_register (plugin, "auparse", GST_RANK_SECONDARY,
736
          GST_TYPE_AU_PARSE)) {
737
738
    return FALSE;
  }
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
739
740
741
742

  return TRUE;
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
743
744
745
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
    GST_VERSION_MINOR,
    "auparse",
746
747
    "parses au streams", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
    GST_PACKAGE_ORIGIN)