1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
3 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
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.
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.
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.
27 #include <gstwavparse.h>
29 static void gst_wavparse_base_init (gpointer g_class);
30 static void gst_wavparse_class_init (GstWavParseClass *klass);
31 static void gst_wavparse_init (GstWavParse *wavparse);
33 static GstElementStateReturn
34 gst_wavparse_change_state (GstElement *element);
36 static const GstFormat* gst_wavparse_get_formats (GstPad *pad);
37 static const GstQueryType *
38 gst_wavparse_get_query_types (GstPad *pad);
39 static gboolean gst_wavparse_pad_query (GstPad *pad,
43 static gboolean gst_wavparse_pad_convert (GstPad *pad,
46 GstFormat *dest_format,
49 static void gst_wavparse_loop (GstElement *element);
50 static const GstEventMask*
51 gst_wavparse_get_event_masks (GstPad *pad);
52 static gboolean gst_wavparse_srcpad_event (GstPad *pad, GstEvent *event);
53 static void gst_wavparse_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
55 /* elementfactory information */
56 static GstElementDetails gst_wavparse_details = GST_ELEMENT_DETAILS (
59 "Parse a .wav file into raw audio",
60 "Erik Walthinsen <omega@cse.ogi.edu>"
63 static GstStaticPadTemplate sink_template_factory =
64 GST_STATIC_PAD_TEMPLATE (
68 GST_STATIC_CAPS ("audio/x-wav")
71 static GstStaticPadTemplate src_template_factory =
72 GST_STATIC_PAD_TEMPLATE (
78 "endianness = (int) little_endian, "
79 "signed = (boolean) { true, false }, "
80 "width = (int) { 8, 16 }, "
81 "depth = (int) { 8, 16 }, "
82 "rate = (int) [ 8000, 48000 ], "
83 "channels = (int) [ 1, 2 ]; "
85 "mpegversion = (int) 1, "
86 "layer = (int) [ 1, 3 ], "
87 "rate = (int) [ 8000, 48000 ], "
88 "channels = (int) [ 1, 2 ]; "
90 "rate = (int) [ 8000, 48000 ], "
91 "channels = (int) [ 1, 2 ]; "
93 "rate = (int) [ 8000, 48000 ], "
94 "channels = (int) [ 1, 2 ]"
98 /* WavParse signals and args */
108 static GstElementClass *parent_class = NULL;
109 /*static guint gst_wavparse_signals[LAST_SIGNAL] = { 0 }; */
112 gst_wavparse_get_type (void)
114 static GType wavparse_type = 0;
116 if (!wavparse_type) {
117 static const GTypeInfo wavparse_info = {
118 sizeof(GstWavParseClass),
119 gst_wavparse_base_init,
121 (GClassInitFunc) gst_wavparse_class_init,
126 (GInstanceInitFunc) gst_wavparse_init,
128 wavparse_type = g_type_register_static (GST_TYPE_ELEMENT, "GstWavParse", &wavparse_info, 0);
130 return wavparse_type;
135 gst_wavparse_base_init (gpointer g_class)
137 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
139 gst_element_class_set_details (element_class, &gst_wavparse_details);
141 /* register src pads */
142 gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&sink_template_factory));
143 gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&src_template_factory));
146 gst_wavparse_class_init (GstWavParseClass *klass)
148 GstElementClass *gstelement_class;
149 GObjectClass *object_class;
151 gstelement_class = (GstElementClass*) klass;
152 object_class = (GObjectClass *) klass;
154 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
156 object_class->get_property = gst_wavparse_get_property;
157 gstelement_class->change_state = gst_wavparse_change_state;
161 gst_wavparse_init (GstWavParse *wavparse)
164 wavparse->sinkpad = gst_pad_new_from_template (gst_static_pad_template_get (&sink_template_factory), "sink");
165 gst_element_add_pad (GST_ELEMENT (wavparse), wavparse->sinkpad);
167 gst_pad_set_formats_function (wavparse->sinkpad, gst_wavparse_get_formats);
168 gst_pad_set_convert_function (wavparse->sinkpad, gst_wavparse_pad_convert);
169 gst_pad_set_query_type_function (wavparse->sinkpad,
170 gst_wavparse_get_query_types);
171 gst_pad_set_query_function (wavparse->sinkpad, gst_wavparse_pad_query);
174 wavparse->srcpad = gst_pad_new_from_template (gst_static_pad_template_get (&src_template_factory), "src");
175 gst_pad_use_explicit_caps (wavparse->srcpad);
176 gst_element_add_pad (GST_ELEMENT (wavparse), wavparse->srcpad);
177 gst_pad_set_formats_function (wavparse->srcpad, gst_wavparse_get_formats);
178 gst_pad_set_convert_function (wavparse->srcpad, gst_wavparse_pad_convert);
179 gst_pad_set_query_type_function (wavparse->srcpad,
180 gst_wavparse_get_query_types);
181 gst_pad_set_query_function (wavparse->srcpad, gst_wavparse_pad_query);
182 gst_pad_set_event_function (wavparse->srcpad, gst_wavparse_srcpad_event);
183 gst_pad_set_event_mask_function (wavparse->srcpad, gst_wavparse_get_event_masks);
185 gst_element_set_loop_function (GST_ELEMENT (wavparse), gst_wavparse_loop);
187 wavparse->state = GST_WAVPARSE_UNKNOWN;
189 wavparse->seek_pending = FALSE;
190 wavparse->seek_offset = 0;
194 gst_wavparse_get_property (GObject *object,
199 GstWavParse *wavparse;
201 wavparse = GST_WAVPARSE (object);
211 gst_wavparse_parse_adtl (GstWavParse *wavparse,
215 GstByteStream *bs = wavparse->bs;
216 gst_riff_chunk *temp_chunk, chunk;
218 struct _gst_riff_labl labl, *temp_labl;
219 struct _gst_riff_ltxt ltxt, *temp_ltxt;
220 struct _gst_riff_note note, *temp_note;
223 GstPropsEntry *entry;
227 props = wavparse->metadata->properties;
230 got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (gst_riff_chunk));
231 if (got_bytes != sizeof (gst_riff_chunk)) {
234 temp_chunk = (gst_riff_chunk *) tempdata;
236 chunk.id = GUINT32_FROM_LE (temp_chunk->id);
237 chunk.size = GUINT32_FROM_LE (temp_chunk->size);
239 if (chunk.size == 0) {
240 gst_bytestream_flush (bs, sizeof (gst_riff_chunk));
241 len -= sizeof (gst_riff_chunk);
246 case GST_RIFF_adtl_labl:
247 got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (struct _gst_riff_labl));
248 if (got_bytes != sizeof (struct _gst_riff_labl)) {
252 temp_labl = (struct _gst_riff_labl *) tempdata;
253 labl.id = GUINT32_FROM_LE (temp_labl->id);
254 labl.size = GUINT32_FROM_LE (temp_labl->size);
255 labl.identifier = GUINT32_FROM_LE (temp_labl->identifier);
257 gst_bytestream_flush (bs, sizeof (struct _gst_riff_labl));
258 len -= sizeof (struct _gst_riff_labl);
260 got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, labl.size - 4);
261 if (got_bytes != labl.size - 4) {
265 label_name = (char *) tempdata;
267 gst_bytestream_flush (bs, ((labl.size - 4) + 1) & ~1);
268 len -= (( (labl.size - 4) + 1) & ~1);
270 new_caps = gst_caps_new ("label",
271 "application/x-gst-metadata",
273 "identifier", G_TYPE_INT (labl.identifier),
274 "name", G_TYPE_STRING (label_name),
277 if (gst_props_get (props, "labels", &caps, NULL)) {
278 caps = g_list_append (caps, new_caps);
280 caps = g_list_append (NULL, new_caps);
282 entry = gst_props_entry_new ("labels", GST_PROPS_GLIST (caps));
283 gst_props_add_entry (props, entry);
288 case GST_RIFF_adtl_ltxt:
289 got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (struct _gst_riff_ltxt));
290 if (got_bytes != sizeof (struct _gst_riff_ltxt)) {
294 temp_ltxt = (struct _gst_riff_ltxt *) tempdata;
295 ltxt.id = GUINT32_FROM_LE (temp_ltxt->id);
296 ltxt.size = GUINT32_FROM_LE (temp_ltxt->size);
297 ltxt.identifier = GUINT32_FROM_LE (temp_ltxt->identifier);
298 ltxt.length = GUINT32_FROM_LE (temp_ltxt->length);
299 ltxt.purpose = GUINT32_FROM_LE (temp_ltxt->purpose);
300 ltxt.country = GUINT16_FROM_LE (temp_ltxt->country);
301 ltxt.language = GUINT16_FROM_LE (temp_ltxt->language);
302 ltxt.dialect = GUINT16_FROM_LE (temp_ltxt->dialect);
303 ltxt.codepage = GUINT16_FROM_LE (temp_ltxt->codepage);
305 gst_bytestream_flush (bs, sizeof (struct _gst_riff_ltxt));
306 len -= sizeof (struct _gst_riff_ltxt);
308 if (ltxt.size - 20 > 0) {
309 got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, ltxt.size - 20);
310 if (got_bytes != ltxt.size - 20) {
314 gst_bytestream_flush (bs, ((ltxt.size - 20) + 1) & ~1);
315 len -= (( (ltxt.size - 20) + 1) & ~1);
317 label_name = (char *) tempdata;
322 new_caps = gst_caps_new ("ltxt",
323 "application/x-gst-metadata",
325 "identifier", G_TYPE_INT (ltxt.identifier),
326 "name", G_TYPE_STRING (label_name),
327 "length", G_TYPE_INT (ltxt.length),
330 if (gst_props_get (props, "ltxts", &caps, NULL)) {
331 caps = g_list_append (caps, new_caps);
333 caps = g_list_append (NULL, new_caps);
335 entry = gst_props_entry_new ("ltxts", GST_PROPS_GLIST (caps));
336 gst_props_add_entry (props, entry);
341 case GST_RIFF_adtl_note:
342 got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (struct _gst_riff_note));
343 if (got_bytes != sizeof (struct _gst_riff_note)) {
347 temp_note = (struct _gst_riff_note *) tempdata;
348 note.id = GUINT32_FROM_LE (temp_note->id);
349 note.size = GUINT32_FROM_LE (temp_note->size);
350 note.identifier = GUINT32_FROM_LE (temp_note->identifier);
352 gst_bytestream_flush (bs, sizeof (struct _gst_riff_note));
353 len -= sizeof (struct _gst_riff_note);
355 got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, note.size - 4);
356 if (got_bytes != note.size - 4) {
360 gst_bytestream_flush (bs, ((note.size - 4) + 1) & ~1);
361 len -= (( (note.size - 4) + 1) & ~1);
363 label_name = (char *) tempdata;
365 new_caps = gst_caps_new ("note",
366 "application/x-gst-metadata",
368 "identifier", G_TYPE_INT (note.identifier),
369 "name", G_TYPE_STRING (label_name),
372 if (gst_props_get (props, "notes", &caps, NULL)) {
373 caps = g_list_append (caps, new_caps);
375 caps = g_list_append (NULL, new_caps);
377 entry = gst_props_entry_new ("notes", GST_PROPS_GLIST (caps));
378 gst_props_add_entry (props, entry);
384 g_print ("Unknown chunk: " GST_FOURCC_FORMAT "\n", GST_FOURCC_ARGS(chunk.id));
389 g_object_notify (G_OBJECT (wavparse), "metadata");
395 gst_wavparse_parse_info (GstWavParse *wavparse,
398 gst_riff_chunk *temp_chunk, chunk;
399 GstByteStream *bs = wavparse->bs;
405 got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (gst_riff_chunk));
406 temp_chunk = (gst_riff_chunk *) tempdata;
408 chunk.id = GUINT32_FROM_LE (temp_chunk->id);
409 chunk.size = GUINT32_FROM_LE (temp_chunk->size);
411 gst_bytestream_flush (bs, sizeof (gst_riff_chunk));
412 if (got_bytes != sizeof (gst_riff_chunk)) {
416 /* move our pointer on past the header */
417 len -= sizeof (gst_riff_chunk);
419 if (chunk.size == 0) {
423 got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, chunk.size);
424 name = (char *) tempdata;
425 if (got_bytes != chunk.size) {
429 /* move our pointer on past the data ... on an even boundary */
430 gst_bytestream_flush (bs, (chunk.size + 1) & ~1);
431 len -= ((chunk.size + 1) & ~1);
433 /* We now have an info string in 'name' of type chunk.id
436 case GST_RIFF_INFO_IARL:
440 case GST_RIFF_INFO_IART:
444 case GST_RIFF_INFO_ICMS:
445 type = "Commissioner";
448 case GST_RIFF_INFO_ICMT:
452 case GST_RIFF_INFO_ICOP:
456 case GST_RIFF_INFO_ICRD:
457 type = "Creation Date";
460 case GST_RIFF_INFO_IENG:
464 case GST_RIFF_INFO_IGNR:
468 case GST_RIFF_INFO_IKEY:
472 case GST_RIFF_INFO_INAM:
473 type = "Title"; /* name */
476 case GST_RIFF_INFO_IPRD:
480 case GST_RIFF_INFO_ISBJ:
484 case GST_RIFF_INFO_ISFT:
488 case GST_RIFF_INFO_ITCH:
493 g_print ("Unknown: %4.4s\n", (char *) &chunk.id);
499 GstPropsEntry *entry;
501 entry = gst_props_entry_new (type, G_TYPE_STRING (name));
502 gst_props_add_entry (wavparse->metadata->properties, entry);
506 g_object_notify (G_OBJECT (wavparse), "metadata");
512 gst_wavparse_parse_cues (GstWavParse *wavparse,
516 GstByteStream *bs = wavparse->bs;
517 struct _gst_riff_cue *temp_cue, cue;
518 struct _gst_riff_cuepoints *points;
522 GstPropsEntry *entry;
527 got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (struct _gst_riff_cue));
528 temp_cue = (struct _gst_riff_cue *) tempdata;
530 /* fixup for our big endian friends */
531 cue.id = GUINT32_FROM_LE (temp_cue->id);
532 cue.size = GUINT32_FROM_LE (temp_cue->size);
533 cue.cuepoints = GUINT32_FROM_LE (temp_cue->cuepoints);
535 gst_bytestream_flush (bs, sizeof (struct _gst_riff_cue));
536 if (got_bytes != sizeof (struct _gst_riff_cue)) {
540 len -= sizeof (struct _gst_riff_cue);
542 /* -4 because cue.size contains the cuepoints size
543 and we've already flushed that out of the system */
544 required = cue.size - 4;
545 got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, required);
546 gst_bytestream_flush (bs, ((required) + 1) & ~1);
547 if (got_bytes != required) {
551 len -= ( ((cue.size - 4) + 1) & ~1);
553 /* now we have an array of struct _gst_riff_cuepoints in tempdata */
554 points = (struct _gst_riff_cuepoints *) tempdata;
556 for (i = 0; i < cue.cuepoints; i++) {
559 caps = gst_caps_new ("cues",
560 "application/x-gst-metadata",
562 "identifier", G_TYPE_INT (points[i].identifier),
563 "position", G_TYPE_INT (points[i].offset),
565 cues = g_list_append (cues, caps);
568 entry = gst_props_entry_new ("cues", GST_PROPS_GLIST (cues));
569 gst_props_add_entry (wavparse->metadata->properties, entry);
572 g_object_notify (G_OBJECT (wavparse), "metadata");
577 gst_wavparse_parse_fmt (GstWavParse *wavparse, guint size)
579 GstWavParseFormat *format;
580 GstCaps *caps = NULL;
582 GstByteStream *bs = wavparse->bs;
585 got_bytes = gst_bytestream_peek_bytes (bs, &fmtdata, sizeof (GstWavParseFormat));
586 format = (GstWavParseFormat *) fmtdata;
588 if (got_bytes == sizeof (GstWavParseFormat)) {
589 gst_bytestream_flush (bs, size);
590 wavparse->bps = GUINT16_FROM_LE (format->wBlockAlign);
591 wavparse->rate = GUINT32_FROM_LE (format->dwSamplesPerSec);
592 wavparse->channels = GUINT16_FROM_LE (format->wChannels);
593 wavparse->width = GUINT16_FROM_LE (format->wBitsPerSample);
594 wavparse->format = GINT16_FROM_LE (format->wFormatTag);
596 /* set the caps on the src pad */
597 /* FIXME: handle all of the other formats as well */
598 switch (wavparse->format) {
599 case GST_RIFF_WAVE_FORMAT_ALAW:
600 case GST_RIFF_WAVE_FORMAT_MULAW: {
601 char *mime = (wavparse->format == GST_RIFF_WAVE_FORMAT_ALAW) ?
602 "audio/x-alaw" : "audio/x-mulaw";
603 if (wavparse->width != 8) {
604 g_warning ("Ignoring invalid width %d", wavparse->width);
608 caps = gst_caps_new_simple (mime,
609 "rate", G_TYPE_INT, wavparse->rate,
610 "channels", G_TYPE_INT, wavparse->channels,
615 case GST_RIFF_WAVE_FORMAT_PCM:
616 caps = gst_caps_new_simple ("audio/x-raw-int",
617 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
618 "signed", G_TYPE_BOOLEAN, (wavparse->width > 8) ? TRUE : FALSE,
619 "width", G_TYPE_INT, wavparse->width,
620 "depth", G_TYPE_INT, wavparse->width,
621 "rate", G_TYPE_INT, wavparse->rate,
622 "channels", G_TYPE_INT, wavparse->channels,
626 case GST_RIFF_WAVE_FORMAT_MPEGL12:
627 case GST_RIFF_WAVE_FORMAT_MPEGL3: {
628 int layer = (wavparse->format == GST_RIFF_WAVE_FORMAT_MPEGL12) ? 2 : 3;
630 caps = gst_caps_new_simple ("audio/mpeg",
631 "mpegversion", G_TYPE_INT, 1,
632 "layer", G_TYPE_INT, layer,
633 "rate", G_TYPE_INT, wavparse->rate,
634 "channels", G_TYPE_INT, wavparse->channels,
640 GST_ELEMENT_ERROR (wavparse, STREAM, NOT_IMPLEMENTED, (NULL), ("format %d not handled", wavparse->format));
645 gst_pad_set_explicit_caps (wavparse->srcpad, caps);
646 gst_caps_free (caps);
649 GST_DEBUG ("frequency %d, channels %d", wavparse->rate, wavparse->channels);
654 gst_wavparse_handle_sink_event (GstWavParse *wavparse)
661 gst_bytestream_get_status (wavparse->bs, &remaining, &event);
663 type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
664 GST_DEBUG ("wavparse: event %p %d", event, type);
668 gst_bytestream_flush (wavparse->bs, remaining);
669 gst_pad_event_default (wavparse->sinkpad, event);
673 case GST_EVENT_FLUSH:
674 g_warning ("Wavparse: Flush event");
678 g_warning ("Wavparse: Unhandled event %d", type);
682 gst_event_unref (event);
689 gst_wavparse_loop (GstElement *element)
691 GstWavParse *wavparse;
697 wavparse = GST_WAVPARSE (element);
701 if (wavparse->seek_pending) {
702 GST_DEBUG ("wavparse: seek pending to %" G_GINT64_FORMAT " %08llx",
703 wavparse->seek_offset,
704 (unsigned long long) wavparse->seek_offset);
706 if (!gst_bytestream_seek (bs, wavparse->seek_offset, GST_SEEK_METHOD_SET)) {
707 GST_INFO ("wavparse: Could not seek");
710 wavparse->seek_pending = FALSE;
713 if (wavparse->state == GST_WAVPARSE_DATA) {
717 /* This seems to want the whole chunk,
718 Will this screw up streaming?
719 Does anyone care about streaming wavs?
720 FIXME: Should we have a decent buffer size? */
722 #define MAX_BUFFER_SIZE 1024
724 if (wavparse->dataleft > 0) {
725 desired = MIN (wavparse->dataleft, MAX_BUFFER_SIZE);
726 got_bytes = gst_bytestream_peek (bs, &buf, desired);
728 if (got_bytes != desired) {
732 gst_bytestream_get_status (bs, &remaining, &event);
733 if (event && GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
734 gst_pad_event_default (wavparse->sinkpad, event);
736 GST_ELEMENT_ERROR (element, RESOURCE, READ, (NULL), (NULL));
741 wavparse->dataleft -= got_bytes;
742 wavparse->byteoffset += got_bytes;
744 gst_bytestream_flush (bs, got_bytes);
746 gst_pad_push (wavparse->srcpad, GST_DATA (buf));
749 wavparse->state = GST_WAVPARSE_OTHER;
754 gst_riff_riff *temp_chunk;
758 /* read first two dwords to get chunktype and size */
760 got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (gst_riff_chunk));
761 temp_chunk = (gst_riff_riff *) tempdata;
763 if (got_bytes < sizeof (gst_riff_chunk)) {
764 if (!gst_wavparse_handle_sink_event (wavparse)) {
772 chunk.id = GUINT32_FROM_LE (temp_chunk->id);
773 chunk.size = GUINT32_FROM_LE (temp_chunk->size);
776 case GST_RIFF_TAG_RIFF:
777 case GST_RIFF_TAG_LIST:
778 /* Read complete list chunk */
780 got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (gst_riff_list));
781 temp_chunk = (gst_riff_riff *) tempdata;
782 if (got_bytes < sizeof (gst_riff_list)) {
783 if (!gst_wavparse_handle_sink_event (wavparse)) {
791 chunk.type = GUINT32_FROM_LE (temp_chunk->type);
792 skipsize = sizeof (gst_riff_list);
795 case GST_RIFF_TAG_cue:
800 skipsize = sizeof (gst_riff_chunk);
803 gst_bytestream_flush (bs, skipsize);
806 /* need to flush an even number of bytes at the end */
807 flush = (chunk.size + 1) & ~1;
809 switch (wavparse->state) {
810 case GST_WAVPARSE_START:
811 if (chunk.id != GST_RIFF_TAG_RIFF &&
812 chunk.type != GST_RIFF_RIFF_WAVE) {
813 GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL),
814 ("chunk.id %08x chunk.type %08x", chunk.id, chunk.type));
818 wavparse->state = GST_WAVPARSE_OTHER;
819 /* We are not going to flush lists */
823 case GST_WAVPARSE_OTHER:
824 GST_DEBUG ("riff tag: %4.4s %08x", (char *) &chunk.id, chunk.size);
827 case GST_RIFF_TAG_data:
828 wavparse->state = GST_WAVPARSE_DATA;
829 wavparse->dataleft = chunk.size;
830 wavparse->byteoffset = 0;
834 case GST_RIFF_TAG_fmt:
835 gst_wavparse_parse_fmt (wavparse, chunk.size);
839 case GST_RIFF_TAG_cue:
840 //gst_wavparse_parse_cues (wavparse, chunk.size);
843 case GST_RIFF_TAG_LIST:
844 GST_DEBUG ("list type: %4.4s", (char *) &chunk.type);
845 switch (chunk.type) {
846 case GST_RIFF_LIST_INFO:
847 //gst_wavparse_parse_info (wavparse, chunk.size - 4);
852 case GST_RIFF_LIST_adtl:
853 //gst_wavparse_parse_adtl (wavparse, chunk.size - 4);
863 GST_DEBUG (" ***** unknown chunkid %08x", chunk.id);
869 case GST_WAVPARSE_DATA:
870 /* Should have been handled up there ^^^^ */
876 g_warning ("Unknown state %d\n", wavparse->state);
877 //GST_DEBUG (" ***** unknown chunkid %08x", chunk.id);
884 res = gst_bytestream_flush (bs, flush);
889 gst_bytestream_get_status (bs, &remaining, &event);
890 gst_event_unref (event);
895 /* convert and query stuff */
896 static const GstFormat *
897 gst_wavparse_get_formats (GstPad *pad)
899 static GstFormat formats[] = {
902 GST_FORMAT_DEFAULT, /* a "frame", ie a set of samples per Hz */
910 gst_wavparse_pad_convert (GstPad *pad,
911 GstFormat src_format, gint64 src_value,
912 GstFormat *dest_format, gint64 *dest_value)
914 gint bytes_per_sample;
916 GstWavParse *wavparse;
917 const GstFormat *formats;
918 gboolean src_format_ok = FALSE;
919 gboolean dest_format_ok = FALSE;
921 wavparse = GST_WAVPARSE (gst_pad_get_parent (pad));
923 bytes_per_sample = wavparse->channels * wavparse->width / 8;
924 if (bytes_per_sample == 0) {
925 GST_DEBUG ("bytes_per_sample 0, probably an mp3 - channels %d, width %d",
926 wavparse->channels, wavparse->width);
929 byterate = (glong) (bytes_per_sample * wavparse->rate);
931 g_warning ("byterate is 0, internal error\n");
934 GST_DEBUG ("bytes per sample: %d", bytes_per_sample);
935 /* check if both src_format and sink_format are in the supported formats */
936 formats = gst_pad_get_formats (pad);
938 while (formats && *formats) {
939 if (src_format == *formats) { src_format_ok = TRUE; }
940 if (*dest_format == *formats) { dest_format_ok = TRUE; }
943 if (!src_format_ok || !dest_format_ok) {
944 GST_DEBUG ("src or dest format not supported");
949 switch (src_format) {
950 case GST_FORMAT_BYTES:
951 if (*dest_format == GST_FORMAT_DEFAULT)
952 *dest_value = src_value / bytes_per_sample;
953 else if (*dest_format == GST_FORMAT_TIME)
954 *dest_value = src_value * GST_SECOND / byterate;
956 GST_DEBUG ("can't convert from bytes to other than units/time");
961 case GST_FORMAT_DEFAULT:
962 if (*dest_format == GST_FORMAT_BYTES)
963 *dest_value = src_value * bytes_per_sample;
964 else if (*dest_format == GST_FORMAT_TIME)
965 *dest_value = src_value * GST_SECOND / wavparse->rate;
967 GST_DEBUG ("can't convert from units to other than bytes/time");
971 case GST_FORMAT_TIME:
972 if (*dest_format == GST_FORMAT_BYTES)
973 *dest_value = src_value * byterate / GST_SECOND;
974 else if (*dest_format == GST_FORMAT_DEFAULT)
975 *dest_value = src_value * wavparse->rate / GST_SECOND;
977 GST_DEBUG ("can't convert from time to other than bytes/units");
981 *dest_value = *dest_value & ~(bytes_per_sample - 1);
984 g_warning ("unhandled format for wavparse\n");
990 static const GstQueryType *
991 gst_wavparse_get_query_types (GstPad *pad)
993 static const GstQueryType types[] = {
1001 /* handle queries for location and length in requested format */
1003 gst_wavparse_pad_query (GstPad *pad, GstQueryType type,
1004 GstFormat *format, gint64 *value)
1006 GstFormat peer_format = GST_FORMAT_BYTES;
1008 GstWavParse *wavparse;
1010 /* probe sink's peer pad, convert value, and that's it :) */
1011 /* FIXME: ideally we'd loop over possible formats of peer instead
1012 * of only using BYTE */
1014 /* only support byte, time and unit queries */
1015 wavparse = GST_WAVPARSE (gst_pad_get_parent (pad));
1016 if (!gst_pad_query (GST_PAD_PEER (wavparse->sinkpad), type,
1017 &peer_format, &peer_value)) {
1018 GST_DEBUG ("Could not query sink pad's peer");
1021 if (!gst_pad_convert (wavparse->sinkpad, peer_format, peer_value,
1023 GST_DEBUG ("Could not convert sink pad's peer");
1026 GST_DEBUG ("pad_query done, value %" G_GINT64_FORMAT "\n", *value);
1030 static const GstEventMask*
1031 gst_wavparse_get_event_masks (GstPad *pad)
1033 static const GstEventMask gst_wavparse_src_event_masks[] = {
1034 { GST_EVENT_SEEK, GST_SEEK_METHOD_SET |
1035 GST_SEEK_FLAG_FLUSH },
1038 return gst_wavparse_src_event_masks;
1042 gst_wavparse_srcpad_event (GstPad *pad, GstEvent *event)
1045 GstWavParse *wavparse = GST_WAVPARSE (GST_PAD_PARENT (pad));
1046 gboolean res = FALSE;
1048 GST_DEBUG ("event %d", GST_EVENT_TYPE (event));
1050 switch (GST_EVENT_TYPE (event)) {
1051 case GST_EVENT_SEEK:
1056 /* we can only seek when in the DATA state */
1057 if (wavparse->state != GST_WAVPARSE_DATA) {
1061 format = GST_FORMAT_BYTES;
1063 /* bring format to bytes for the peer element,
1064 * FIXME be smarter here */
1065 res = gst_pad_convert (pad,
1066 GST_EVENT_SEEK_FORMAT (event),
1067 GST_EVENT_SEEK_OFFSET (event),
1072 /* ok, seek worked, update our state */
1073 wavparse->seek_offset = byteoffset;
1074 wavparse->seek_pending = TRUE;
1075 wavparse->need_discont = TRUE;
1083 gst_event_unref (event);
1090 static GstElementStateReturn
1091 gst_wavparse_change_state (GstElement *element)
1093 GstWavParse *wavparse = GST_WAVPARSE (element);
1095 switch (GST_STATE_TRANSITION (element)) {
1096 case GST_STATE_NULL_TO_READY:
1098 case GST_STATE_READY_TO_PAUSED:
1099 wavparse->bs = gst_bytestream_new (wavparse->sinkpad);
1100 wavparse->state = GST_WAVPARSE_START;
1102 case GST_STATE_PAUSED_TO_PLAYING:
1104 case GST_STATE_PLAYING_TO_PAUSED:
1106 case GST_STATE_PAUSED_TO_READY:
1107 gst_bytestream_destroy (wavparse->bs);
1108 wavparse->state = GST_WAVPARSE_UNKNOWN;
1110 wavparse->seek_pending = FALSE;
1111 wavparse->seek_offset = 0;
1113 case GST_STATE_READY_TO_NULL:
1117 if (GST_ELEMENT_CLASS (parent_class)->change_state)
1118 return GST_ELEMENT_CLASS (parent_class)->change_state (element);
1120 return GST_STATE_SUCCESS;
1124 plugin_init (GstPlugin *plugin)
1126 if (!gst_library_load ("gstbytestream")) {
1130 return gst_element_register (plugin, "wavparse", GST_RANK_SECONDARY, GST_TYPE_WAVPARSE);
1137 "Parse a .wav file into raw audio",