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., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 /**
22 * SECTION:element-auparse
23 * @title: auparse
24 *
25 * Parses .au files mostly originating from sun os based computers.
26 */
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include "gstauparse.h"
36 #include <gst/audio/audio.h>
37
38 GST_DEBUG_CATEGORY_STATIC (auparse_debug);
39 #define GST_CAT_DEFAULT (auparse_debug)
40
41 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
42 GST_PAD_SINK,
43 GST_PAD_ALWAYS,
44 GST_STATIC_CAPS ("audio/x-au")
45 );
46
47 #define GST_AU_PARSE_RAW_PAD_TEMPLATE_CAPS \
48 "audio/x-raw, " \
49 "format= (string) { S8, S16LE, S16BE, S24LE, S24BE, " \
50 "S32LE, S32BE, F32LE, F32BE, " \
51 "F64LE, F64BE }, " \
52 "rate = (int) [ 8000, 192000 ], " \
53 "channels = (int) 1, " \
54 "layout = (string) interleaved;" \
55 "audio/x-raw, " \
56 "format= (string) { S8, S16LE, S16BE, S24LE, S24BE, " \
57 "S32LE, S32BE, F32LE, F32BE, " \
58 "F64LE, F64BE }, " \
59 "rate = (int) [ 8000, 192000 ], " \
60 "channels = (int) 2, " \
61 "channel-mask = (bitmask) 0x3," \
62 "layout = (string) interleaved"
63
64 #define GST_AU_PARSE_ALAW_PAD_TEMPLATE_CAPS \
65 "audio/x-alaw, " \
66 "rate = (int) [ 8000, 192000 ], " \
67 "channels = (int) [ 1, 2 ]"
68
69 #define GST_AU_PARSE_MULAW_PAD_TEMPLATE_CAPS \
70 "audio/x-mulaw, " \
71 "rate = (int) [ 8000, 192000 ], " \
72 "channels = (int) [ 1, 2 ]"
73
74 /* Nothing to decode those ADPCM streams for now */
75 #define GST_AU_PARSE_ADPCM_PAD_TEMPLATE_CAPS \
76 "audio/x-adpcm, " \
77 "layout = (string) { g721, g722, g723_3, g723_5 }"
78
79 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
80 GST_PAD_SRC,
81 GST_PAD_ALWAYS,
82 GST_STATIC_CAPS (GST_AU_PARSE_RAW_PAD_TEMPLATE_CAPS "; "
83 GST_AU_PARSE_ALAW_PAD_TEMPLATE_CAPS ";"
84 GST_AU_PARSE_MULAW_PAD_TEMPLATE_CAPS ";"
85 GST_AU_PARSE_ADPCM_PAD_TEMPLATE_CAPS));
86
87
88 static void gst_au_parse_dispose (GObject * object);
89 static GstFlowReturn gst_au_parse_chain (GstPad * pad, GstObject * parent,
90 GstBuffer * buf);
91 static GstStateChangeReturn gst_au_parse_change_state (GstElement * element,
92 GstStateChange transition);
93 static void gst_au_parse_reset (GstAuParse * auparse);
94 static gboolean gst_au_parse_src_query (GstPad * pad, GstObject * parent,
95 GstQuery * query);
96 static gboolean gst_au_parse_src_event (GstPad * pad, GstObject * parent,
97 GstEvent * event);
98 static gboolean gst_au_parse_sink_event (GstPad * pad, GstObject * parent,
99 GstEvent * event);
100 static gboolean gst_au_parse_src_convert (GstAuParse * auparse,
101 GstFormat src_format, gint64 srcval, GstFormat dest_format,
102 gint64 * destval);
103
104 #define gst_au_parse_parent_class parent_class
105 G_DEFINE_TYPE (GstAuParse, gst_au_parse, GST_TYPE_ELEMENT);
106 GST_ELEMENT_REGISTER_DEFINE (auparse, "auparse", GST_RANK_SECONDARY,
107 GST_TYPE_AU_PARSE);
108
109 static void
gst_au_parse_class_init(GstAuParseClass * klass)110 gst_au_parse_class_init (GstAuParseClass * klass)
111 {
112 GObjectClass *gobject_class;
113 GstElementClass *gstelement_class;
114
115 GST_DEBUG_CATEGORY_INIT (auparse_debug, "auparse", 0, ".au parser");
116
117 gobject_class = (GObjectClass *) klass;
118 gstelement_class = (GstElementClass *) klass;
119
120 gobject_class->dispose = gst_au_parse_dispose;
121
122 gstelement_class->change_state =
123 GST_DEBUG_FUNCPTR (gst_au_parse_change_state);
124 gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
125 gst_element_class_add_static_pad_template (gstelement_class, &src_template);
126 gst_element_class_set_static_metadata (gstelement_class,
127 "AU audio demuxer",
128 "Codec/Demuxer/Audio",
129 "Parse an .au file into raw audio",
130 "Erik Walthinsen <omega@cse.ogi.edu>");
131 }
132
133 static void
gst_au_parse_init(GstAuParse * auparse)134 gst_au_parse_init (GstAuParse * auparse)
135 {
136 auparse->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
137 gst_pad_set_chain_function (auparse->sinkpad,
138 GST_DEBUG_FUNCPTR (gst_au_parse_chain));
139 gst_pad_set_event_function (auparse->sinkpad,
140 GST_DEBUG_FUNCPTR (gst_au_parse_sink_event));
141 gst_element_add_pad (GST_ELEMENT (auparse), auparse->sinkpad);
142
143 auparse->srcpad = gst_pad_new_from_static_template (&src_template, "src");
144 gst_pad_set_query_function (auparse->srcpad,
145 GST_DEBUG_FUNCPTR (gst_au_parse_src_query));
146 gst_pad_set_event_function (auparse->srcpad,
147 GST_DEBUG_FUNCPTR (gst_au_parse_src_event));
148 gst_pad_use_fixed_caps (auparse->srcpad);
149 gst_element_add_pad (GST_ELEMENT (auparse), auparse->srcpad);
150
151 auparse->adapter = gst_adapter_new ();
152 gst_au_parse_reset (auparse);
153 }
154
155 static void
gst_au_parse_dispose(GObject * object)156 gst_au_parse_dispose (GObject * object)
157 {
158 GstAuParse *au = GST_AU_PARSE (object);
159
160 if (au->adapter != NULL) {
161 g_object_unref (au->adapter);
162 au->adapter = NULL;
163 }
164 G_OBJECT_CLASS (parent_class)->dispose (object);
165 }
166
167 static void
gst_au_parse_reset(GstAuParse * auparse)168 gst_au_parse_reset (GstAuParse * auparse)
169 {
170 auparse->offset = 0;
171 auparse->buffer_offset = 0;
172 auparse->encoding = 0;
173 auparse->samplerate = 0;
174 auparse->channels = 0;
175
176 gst_adapter_clear (auparse->adapter);
177
178 gst_caps_replace (&auparse->src_caps, NULL);
179
180 /* gst_segment_init (&auparse->segment, GST_FORMAT_TIME); */
181 }
182
183 static void
gst_au_parse_negotiate_srcpad(GstAuParse * auparse,GstCaps * new_caps)184 gst_au_parse_negotiate_srcpad (GstAuParse * auparse, GstCaps * new_caps)
185 {
186 if (auparse->src_caps && gst_caps_is_equal (new_caps, auparse->src_caps)) {
187 GST_LOG_OBJECT (auparse, "same caps, nothing to do");
188 return;
189 }
190
191 gst_caps_replace (&auparse->src_caps, new_caps);
192 GST_DEBUG_OBJECT (auparse, "Changing src pad caps to %" GST_PTR_FORMAT,
193 auparse->src_caps);
194 gst_pad_set_caps (auparse->srcpad, auparse->src_caps);
195
196 return;
197 }
198
199 static GstFlowReturn
gst_au_parse_parse_header(GstAuParse * auparse)200 gst_au_parse_parse_header (GstAuParse * auparse)
201 {
202 GstCaps *tempcaps;
203 guint32 size;
204 guint8 *head;
205 gchar layout[7] = { 0, };
206 GstAudioFormat format = GST_AUDIO_FORMAT_UNKNOWN;
207 gint law = 0;
208 guint endianness;
209
210 head = (guint8 *) gst_adapter_map (auparse->adapter, 24);
211 g_assert (head != NULL);
212
213 GST_DEBUG_OBJECT (auparse, "[%c%c%c%c]", head[0], head[1], head[2], head[3]);
214
215 switch (GST_READ_UINT32_BE (head)) {
216 /* normal format is big endian (au is a Sparc format) */
217 case 0x2e736e64:{ /* ".snd" */
218 endianness = G_BIG_ENDIAN;
219 break;
220 }
221 /* and of course, someone had to invent a little endian
222 * version. Used by DEC systems. */
223 case 0x646e732e: /* dns. */
224 case 0x0064732e:{ /* other source say it is "dns." */
225 endianness = G_LITTLE_ENDIAN;
226 break;
227 }
228 default:{
229 goto unknown_header;
230 }
231 }
232
233 auparse->offset = GST_READ_UINT32_BE (head + 4);
234 /* Do not trust size, could be set to -1 : unknown
235 * otherwise: filesize = size + auparse->offset
236 */
237 size = GST_READ_UINT32_BE (head + 8);
238 auparse->encoding = GST_READ_UINT32_BE (head + 12);
239 auparse->samplerate = GST_READ_UINT32_BE (head + 16);
240 auparse->channels = GST_READ_UINT32_BE (head + 20);
241
242 if (auparse->samplerate < 8000 || auparse->samplerate > 192000)
243 goto unsupported_sample_rate;
244
245 if (auparse->channels < 1 || auparse->channels > 2)
246 goto unsupported_number_of_channels;
247
248 GST_DEBUG_OBJECT (auparse, "offset %" G_GINT64_FORMAT ", size %u, "
249 "encoding %u, frequency %u, channels %u", auparse->offset, size,
250 auparse->encoding, auparse->samplerate, auparse->channels);
251
252 /* Docs:
253 * http://www.opengroup.org/public/pubs/external/auformat.html
254 * http://astronomy.swin.edu.au/~pbourke/dataformats/au/
255 * Solaris headers : /usr/include/audio/au.h
256 * libsndfile : src/au.c
257 *
258 * Samples :
259 * http://www.tsp.ece.mcgill.ca/MMSP/Documents/AudioFormats/AU/Samples.html
260 */
261
262 switch (auparse->encoding) {
263 case 1: /* 8-bit ISDN mu-law G.711 */
264 law = 1;
265 break;
266 case 27: /* 8-bit ISDN A-law G.711 */
267 law = 2;
268 break;
269
270 case 2: /* 8-bit linear PCM, FIXME signed? */
271 format = GST_AUDIO_FORMAT_S8;
272 auparse->sample_size = auparse->channels;
273 break;
274 case 3: /* 16-bit linear PCM */
275 if (endianness == G_LITTLE_ENDIAN)
276 format = GST_AUDIO_FORMAT_S16LE;
277 else
278 format = GST_AUDIO_FORMAT_S16BE;
279 auparse->sample_size = auparse->channels * 2;
280 break;
281 case 4: /* 24-bit linear PCM */
282 if (endianness == G_LITTLE_ENDIAN)
283 format = GST_AUDIO_FORMAT_S24LE;
284 else
285 format = GST_AUDIO_FORMAT_S24BE;
286 auparse->sample_size = auparse->channels * 3;
287 break;
288 case 5: /* 32-bit linear PCM */
289 if (endianness == G_LITTLE_ENDIAN)
290 format = GST_AUDIO_FORMAT_S32LE;
291 else
292 format = GST_AUDIO_FORMAT_S32BE;
293 auparse->sample_size = auparse->channels * 4;
294 break;
295
296 case 6: /* 32-bit IEEE floating point */
297 if (endianness == G_LITTLE_ENDIAN)
298 format = GST_AUDIO_FORMAT_F32LE;
299 else
300 format = GST_AUDIO_FORMAT_F32BE;
301 auparse->sample_size = auparse->channels * 4;
302 break;
303 case 7: /* 64-bit IEEE floating point */
304 if (endianness == G_LITTLE_ENDIAN)
305 format = GST_AUDIO_FORMAT_F64LE;
306 else
307 format = GST_AUDIO_FORMAT_F64BE;
308 auparse->sample_size = auparse->channels * 8;
309 break;
310
311 case 23: /* 4-bit CCITT G.721 ADPCM 32kbps -> modplug/libsndfile (compressed 8-bit mu-law) */
312 strcpy (layout, "g721");
313 break;
314 case 24: /* 8-bit CCITT G.722 ADPCM -> rtp */
315 strcpy (layout, "g722");
316 break;
317 case 25: /* 3-bit CCITT G.723.3 ADPCM 24kbps -> rtp/xine/modplug/libsndfile */
318 strcpy (layout, "g723_3");
319 break;
320 case 26: /* 5-bit CCITT G.723.5 ADPCM 40kbps -> rtp/xine/modplug/libsndfile */
321 strcpy (layout, "g723_5");
322 break;
323
324 case 8: /* Fragmented sample data */
325 case 9: /* AU_ENCODING_NESTED */
326
327 case 10: /* DSP program */
328 case 11: /* DSP 8-bit fixed point */
329 case 12: /* DSP 16-bit fixed point */
330 case 13: /* DSP 24-bit fixed point */
331 case 14: /* DSP 32-bit fixed point */
332
333 case 16: /* AU_ENCODING_DISPLAY : non-audio display data */
334 case 17: /* AU_ENCODING_MULAW_SQUELCH */
335
336 case 18: /* 16-bit linear with emphasis */
337 case 19: /* 16-bit linear compressed (NeXT) */
338 case 20: /* 16-bit linear with emphasis and compression */
339
340 case 21: /* Music kit DSP commands */
341 case 22: /* Music kit DSP commands samples */
342
343 default:
344 goto unknown_format;
345 }
346
347 if (law) {
348 tempcaps =
349 gst_caps_new_simple ((law == 1) ? "audio/x-mulaw" : "audio/x-alaw",
350 "rate", G_TYPE_INT, auparse->samplerate,
351 "channels", G_TYPE_INT, auparse->channels, NULL);
352 auparse->sample_size = auparse->channels;
353 } else if (format != GST_AUDIO_FORMAT_UNKNOWN) {
354 GstCaps *templ_caps = gst_pad_get_pad_template_caps (auparse->srcpad);
355 GstCaps *intersection;
356
357 tempcaps = gst_caps_new_simple ("audio/x-raw",
358 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
359 "rate", G_TYPE_INT, auparse->samplerate,
360 "channels", G_TYPE_INT, auparse->channels, NULL);
361
362 intersection = gst_caps_intersect (tempcaps, templ_caps);
363 gst_caps_unref (tempcaps);
364 gst_caps_unref (templ_caps);
365 tempcaps = intersection;
366 } else if (layout[0]) {
367 tempcaps = gst_caps_new_simple ("audio/x-adpcm",
368 "layout", G_TYPE_STRING, layout, NULL);
369 auparse->sample_size = 0;
370 } else
371 goto unknown_format;
372
373 GST_DEBUG_OBJECT (auparse, "sample_size=%d", auparse->sample_size);
374
375 gst_au_parse_negotiate_srcpad (auparse, tempcaps);
376
377 GST_DEBUG_OBJECT (auparse, "offset=%" G_GINT64_FORMAT, auparse->offset);
378 gst_adapter_unmap (auparse->adapter);
379 gst_adapter_flush (auparse->adapter, auparse->offset);
380
381 gst_caps_unref (tempcaps);
382 return GST_FLOW_OK;
383
384 /* ERRORS */
385 unknown_header:
386 {
387 gst_adapter_unmap (auparse->adapter);
388 GST_ELEMENT_ERROR (auparse, STREAM, WRONG_TYPE, (NULL), (NULL));
389 return GST_FLOW_ERROR;
390 }
391 unsupported_sample_rate:
392 {
393 gst_adapter_unmap (auparse->adapter);
394 GST_ELEMENT_ERROR (auparse, STREAM, FORMAT, (NULL),
395 ("Unsupported samplerate: %u", auparse->samplerate));
396 return GST_FLOW_ERROR;
397 }
398 unsupported_number_of_channels:
399 {
400 gst_adapter_unmap (auparse->adapter);
401 GST_ELEMENT_ERROR (auparse, STREAM, FORMAT, (NULL),
402 ("Unsupported number of channels: %u", auparse->channels));
403 return GST_FLOW_ERROR;
404 }
405 unknown_format:
406 {
407 gst_adapter_unmap (auparse->adapter);
408 GST_ELEMENT_ERROR (auparse, STREAM, FORMAT, (NULL),
409 ("Unsupported encoding: %u", auparse->encoding));
410 return GST_FLOW_ERROR;
411 }
412 }
413
414 #define AU_HEADER_SIZE 24
415
416 static GstFlowReturn
gst_au_parse_chain(GstPad * pad,GstObject * parent,GstBuffer * buf)417 gst_au_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
418 {
419 GstFlowReturn ret = GST_FLOW_OK;
420 GstAuParse *auparse;
421 gint avail, sendnow = 0;
422 gint64 timestamp = 0;
423 gint64 duration = 0;
424 gint64 offset = 0;
425
426 auparse = GST_AU_PARSE (parent);
427
428 GST_LOG_OBJECT (auparse, "got buffer of size %" G_GSIZE_FORMAT,
429 gst_buffer_get_size (buf));
430
431 gst_adapter_push (auparse->adapter, buf);
432 buf = NULL;
433
434 /* if we haven't seen any data yet... */
435 if (!gst_pad_has_current_caps (auparse->srcpad)) {
436 if (gst_adapter_available (auparse->adapter) < AU_HEADER_SIZE) {
437 GST_DEBUG_OBJECT (auparse, "need more data to parse header");
438 ret = GST_FLOW_OK;
439 goto out;
440 }
441
442 ret = gst_au_parse_parse_header (auparse);
443 if (ret != GST_FLOW_OK)
444 goto out;
445
446 if (auparse->need_segment) {
447 gst_pad_push_event (auparse->srcpad,
448 gst_event_new_segment (&auparse->segment));
449 auparse->need_segment = FALSE;
450 }
451 }
452
453 avail = gst_adapter_available (auparse->adapter);
454
455 if (auparse->sample_size > 0) {
456 /* Ensure we push a buffer that's a multiple of the frame size downstream */
457 sendnow = avail - (avail % auparse->sample_size);
458 } else {
459 /* It's something non-trivial (such as ADPCM), we don't understand it, so
460 * just push downstream and assume it will know what to do with it */
461 sendnow = avail;
462 }
463
464 if (sendnow > 0) {
465 GstBuffer *outbuf;
466 gint64 pos;
467
468 outbuf = gst_adapter_take_buffer (auparse->adapter, sendnow);
469 outbuf = gst_buffer_make_writable (outbuf);
470
471 pos = auparse->buffer_offset - auparse->offset;
472 pos = MAX (pos, 0);
473
474 if (auparse->sample_size > 0 && auparse->samplerate > 0) {
475 gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, pos,
476 GST_FORMAT_DEFAULT, &offset);
477 gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, pos,
478 GST_FORMAT_TIME, ×tamp);
479 gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES,
480 sendnow, GST_FORMAT_TIME, &duration);
481
482 GST_BUFFER_OFFSET (outbuf) = offset;
483 GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
484 GST_BUFFER_DURATION (outbuf) = duration;
485 }
486
487 auparse->buffer_offset += sendnow;
488
489 ret = gst_pad_push (auparse->srcpad, outbuf);
490 }
491
492 out:
493
494 return ret;
495 }
496
497 static gboolean
gst_au_parse_src_convert(GstAuParse * auparse,GstFormat src_format,gint64 srcval,GstFormat dest_format,gint64 * destval)498 gst_au_parse_src_convert (GstAuParse * auparse, GstFormat src_format,
499 gint64 srcval, GstFormat dest_format, gint64 * destval)
500 {
501 gboolean ret = TRUE;
502 guint samplesize, rate;
503
504 if (dest_format == src_format) {
505 *destval = srcval;
506 return TRUE;
507 }
508
509 GST_OBJECT_LOCK (auparse);
510 samplesize = auparse->sample_size;
511 rate = auparse->samplerate;
512 GST_OBJECT_UNLOCK (auparse);
513
514 if (samplesize == 0 || rate == 0) {
515 GST_LOG_OBJECT (auparse, "cannot convert, sample_size or rate unknown");
516 return FALSE;
517 }
518
519 switch (src_format) {
520 case GST_FORMAT_BYTES:
521 srcval /= samplesize;
522 /* fallthrough */
523 case GST_FORMAT_DEFAULT:{
524 switch (dest_format) {
525 case GST_FORMAT_DEFAULT:
526 *destval = srcval;
527 break;
528 case GST_FORMAT_BYTES:
529 *destval = srcval * samplesize;
530 break;
531 case GST_FORMAT_TIME:
532 *destval = gst_util_uint64_scale_int (srcval, GST_SECOND, rate);
533 break;
534 default:
535 ret = FALSE;
536 break;
537 }
538 break;
539 }
540 case GST_FORMAT_TIME:{
541 switch (dest_format) {
542 case GST_FORMAT_BYTES:
543 *destval = samplesize *
544 gst_util_uint64_scale_int (srcval, rate, GST_SECOND);
545 break;
546 case GST_FORMAT_DEFAULT:
547 *destval = gst_util_uint64_scale_int (srcval, rate, GST_SECOND);
548 break;
549 default:
550 ret = FALSE;
551 break;
552 }
553 break;
554 }
555 default:{
556 ret = FALSE;
557 break;
558 }
559 }
560
561 if (!ret) {
562 GST_DEBUG_OBJECT (auparse, "could not convert from %s to %s format",
563 gst_format_get_name (src_format), gst_format_get_name (dest_format));
564 }
565
566 return ret;
567 }
568
569 static gboolean
gst_au_parse_src_query(GstPad * pad,GstObject * parent,GstQuery * query)570 gst_au_parse_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
571 {
572 GstAuParse *auparse;
573 gboolean ret = FALSE;
574
575 auparse = GST_AU_PARSE (parent);
576
577 switch (GST_QUERY_TYPE (query)) {
578 case GST_QUERY_DURATION:{
579 GstFormat format;
580 gint64 len, val;
581
582 gst_query_parse_duration (query, &format, NULL);
583 if (!gst_pad_peer_query_duration (auparse->sinkpad, GST_FORMAT_BYTES,
584 &len)) {
585 GST_DEBUG_OBJECT (auparse, "failed to query upstream length");
586 break;
587 }
588 GST_OBJECT_LOCK (auparse);
589 len -= auparse->offset;
590 GST_OBJECT_UNLOCK (auparse);
591
592 ret =
593 gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, len, format,
594 &val);
595
596 if (ret) {
597 gst_query_set_duration (query, format, val);
598 }
599 break;
600 }
601 case GST_QUERY_POSITION:{
602 GstFormat format;
603 gint64 pos, val;
604
605 gst_query_parse_position (query, &format, NULL);
606 if (!gst_pad_peer_query_position (auparse->sinkpad, GST_FORMAT_BYTES,
607 &pos)) {
608 GST_DEBUG_OBJECT (auparse, "failed to query upstream position");
609 break;
610 }
611 GST_OBJECT_LOCK (auparse);
612 pos -= auparse->offset;
613 GST_OBJECT_UNLOCK (auparse);
614
615 ret = gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, pos,
616 format, &val);
617
618 if (ret) {
619 gst_query_set_position (query, format, val);
620 }
621 break;
622 }
623 case GST_QUERY_SEEKING:{
624 GstFormat format;
625
626 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
627 /* FIXME: query duration in 'format'
628 gst_query_set_seeking (query, format, TRUE, 0, duration);
629 */
630 gst_query_set_seeking (query, format, TRUE, 0, GST_CLOCK_TIME_NONE);
631 ret = TRUE;
632 break;
633 }
634 default:
635 ret = gst_pad_query_default (pad, parent, query);
636 break;
637 }
638
639 return ret;
640 }
641
642 static gboolean
gst_au_parse_handle_seek(GstAuParse * auparse,GstEvent * event)643 gst_au_parse_handle_seek (GstAuParse * auparse, GstEvent * event)
644 {
645 GstSeekType start_type, stop_type;
646 GstSeekFlags flags;
647 GstFormat format;
648 gdouble rate;
649 gint64 start, stop;
650 gboolean res;
651
652 gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start,
653 &stop_type, &stop);
654
655 if (format != GST_FORMAT_TIME) {
656 GST_DEBUG_OBJECT (auparse, "only support seeks in TIME format");
657 return FALSE;
658 }
659
660 res = gst_au_parse_src_convert (auparse, GST_FORMAT_TIME, start,
661 GST_FORMAT_BYTES, &start);
662
663 if (stop > 0) {
664 res = gst_au_parse_src_convert (auparse, GST_FORMAT_TIME, stop,
665 GST_FORMAT_BYTES, &stop);
666 }
667
668 GST_INFO_OBJECT (auparse,
669 "seeking: %" G_GINT64_FORMAT " ... %" G_GINT64_FORMAT, start, stop);
670
671 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, start_type, start,
672 stop_type, stop);
673 res = gst_pad_push_event (auparse->sinkpad, event);
674 return res;
675 }
676
677 static gboolean
gst_au_parse_sink_event(GstPad * pad,GstObject * parent,GstEvent * event)678 gst_au_parse_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
679 {
680 GstAuParse *auparse;
681 gboolean ret = TRUE;
682
683 auparse = GST_AU_PARSE (parent);
684
685 switch (GST_EVENT_TYPE (event)) {
686 case GST_EVENT_CAPS:
687 {
688 /* discard, we'll come up with proper src caps */
689 gst_event_unref (event);
690 break;
691 }
692 case GST_EVENT_SEGMENT:
693 {
694 gint64 start, stop, offset = 0;
695 GstSegment segment;
696
697 /* some debug output */
698 gst_event_copy_segment (event, &segment);
699 GST_DEBUG_OBJECT (auparse, "received newsegment %" GST_SEGMENT_FORMAT,
700 &segment);
701
702 start = segment.start;
703 stop = segment.stop;
704 if (auparse->sample_size > 0) {
705 if (start > 0) {
706 offset = start;
707 start -= auparse->offset;
708 start = MAX (start, 0);
709 }
710 if (stop > 0) {
711 stop -= auparse->offset;
712 stop = MAX (stop, 0);
713 }
714 gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, start,
715 GST_FORMAT_TIME, &start);
716 gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, stop,
717 GST_FORMAT_TIME, &stop);
718 }
719
720 GST_INFO_OBJECT (auparse,
721 "new segment: %" GST_TIME_FORMAT " ... %" GST_TIME_FORMAT,
722 GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
723
724 gst_segment_init (&segment, GST_FORMAT_TIME);
725 segment.start = segment.time = start;
726 segment.stop = stop;
727
728 gst_segment_copy_into (&segment, &auparse->segment);
729
730 if (!gst_pad_has_current_caps (auparse->srcpad)) {
731 auparse->need_segment = TRUE;
732 ret = TRUE;
733 } else {
734 auparse->need_segment = FALSE;
735 ret = gst_pad_push_event (auparse->srcpad,
736 gst_event_new_segment (&segment));
737 }
738
739 auparse->buffer_offset = offset;
740
741 gst_event_unref (event);
742 break;
743 }
744 case GST_EVENT_EOS:
745 if (!auparse->srcpad) {
746 GST_ELEMENT_ERROR (auparse, STREAM, WRONG_TYPE,
747 ("No valid input found before end of stream"), (NULL));
748 }
749 /* fall-through */
750 default:
751 ret = gst_pad_event_default (pad, parent, event);
752 break;
753 }
754
755 return ret;
756 }
757
758 static gboolean
gst_au_parse_src_event(GstPad * pad,GstObject * parent,GstEvent * event)759 gst_au_parse_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
760 {
761 GstAuParse *auparse;
762 gboolean ret;
763
764 auparse = GST_AU_PARSE (parent);
765
766 switch (GST_EVENT_TYPE (event)) {
767 case GST_EVENT_SEEK:
768 ret = gst_au_parse_handle_seek (auparse, event);
769 gst_event_unref (event);
770 break;
771 default:
772 ret = gst_pad_event_default (pad, parent, event);
773 break;
774 }
775
776 return ret;
777 }
778
779 static GstStateChangeReturn
gst_au_parse_change_state(GstElement * element,GstStateChange transition)780 gst_au_parse_change_state (GstElement * element, GstStateChange transition)
781 {
782 GstAuParse *auparse = GST_AU_PARSE (element);
783 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
784
785 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
786 if (ret == GST_STATE_CHANGE_FAILURE)
787 return ret;
788
789 switch (transition) {
790 case GST_STATE_CHANGE_PAUSED_TO_READY:
791 gst_au_parse_reset (auparse);
792 default:
793 break;
794 }
795
796 return ret;
797 }
798
799 static gboolean
plugin_init(GstPlugin * plugin)800 plugin_init (GstPlugin * plugin)
801 {
802 if (!GST_ELEMENT_REGISTER (auparse, plugin))
803 return FALSE;
804
805 return TRUE;
806 }
807
808 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
809 GST_VERSION_MINOR,
810 auparse,
811 "parses au streams", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
812 GST_PACKAGE_ORIGIN)
813