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,
614 case GST_RIFF_WAVE_FORMAT_PCM:
615 caps = gst_caps_new_simple ("audio/x-raw-int",
616 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
617 "signed", G_TYPE_BOOLEAN, (wavparse->width > 8) ? TRUE : FALSE,
618 "width", G_TYPE_INT, wavparse->width,
619 "depth", G_TYPE_INT, wavparse->width,
620 "rate", G_TYPE_INT, wavparse->rate,
621 "channels", G_TYPE_INT, wavparse->channels,
625 case GST_RIFF_WAVE_FORMAT_MPEGL12:
626 case GST_RIFF_WAVE_FORMAT_MPEGL3: {
627 int layer = (wavparse->format == GST_RIFF_WAVE_FORMAT_MPEGL12) ? 2 : 3;
629 caps = gst_caps_new_simple ("audio/mpeg",
630 "mpegversion", G_TYPE_INT, 1,
631 "layer", G_TYPE_INT, layer,
632 "rate", G_TYPE_INT, wavparse->rate,
633 "channels", G_TYPE_INT, wavparse->channels,
639 GST_ELEMENT_ERROR (wavparse, STREAM, NOT_IMPLEMENTED, (NULL), ("format %d not handled", wavparse->format));
644 gst_pad_set_explicit_caps (wavparse->srcpad, caps);
646 GST_DEBUG ("frequency %d, channels %d",
647 wavparse->rate, wavparse->channels);
652 gst_wavparse_handle_sink_event (GstWavParse *wavparse)
659 gst_bytestream_get_status (wavparse->bs, &remaining, &event);
661 type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
662 GST_DEBUG ("wavparse: event %p %d", event, type);
666 gst_bytestream_flush (wavparse->bs, remaining);
667 gst_pad_event_default (wavparse->sinkpad, event);
671 case GST_EVENT_FLUSH:
672 g_warning ("Wavparse: Flush event");
676 g_warning ("Wavparse: Unhandled event %d", type);
680 gst_event_unref (event);
687 gst_wavparse_loop (GstElement *element)
689 GstWavParse *wavparse;
695 wavparse = GST_WAVPARSE (element);
699 if (wavparse->seek_pending) {
700 GST_DEBUG ("wavparse: seek pending to %" G_GINT64_FORMAT " %08llx",
701 wavparse->seek_offset,
702 (unsigned long long) wavparse->seek_offset);
704 if (!gst_bytestream_seek (bs, wavparse->seek_offset, GST_SEEK_METHOD_SET)) {
705 GST_INFO ("wavparse: Could not seek");
708 wavparse->seek_pending = FALSE;
711 if (wavparse->state == GST_WAVPARSE_DATA) {
715 /* This seems to want the whole chunk,
716 Will this screw up streaming?
717 Does anyone care about streaming wavs?
718 FIXME: Should we have a decent buffer size? */
720 #define MAX_BUFFER_SIZE 1024
722 if (wavparse->dataleft > 0) {
723 desired = MIN (wavparse->dataleft, MAX_BUFFER_SIZE);
724 got_bytes = gst_bytestream_peek (bs, &buf, desired);
726 if (got_bytes != desired) {
730 gst_bytestream_get_status (bs, &remaining, &event);
731 if (event && GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
732 gst_pad_event_default (wavparse->sinkpad, event);
734 GST_ELEMENT_ERROR (element, RESOURCE, READ, (NULL), (NULL));
739 wavparse->dataleft -= got_bytes;
740 wavparse->byteoffset += got_bytes;
742 gst_bytestream_flush (bs, got_bytes);
744 gst_pad_push (wavparse->srcpad, GST_DATA (buf));
747 wavparse->state = GST_WAVPARSE_OTHER;
752 gst_riff_riff *temp_chunk;
756 /* read first two dwords to get chunktype and size */
758 got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (gst_riff_chunk));
759 temp_chunk = (gst_riff_riff *) tempdata;
761 if (got_bytes < sizeof (gst_riff_chunk)) {
762 if (!gst_wavparse_handle_sink_event (wavparse)) {
770 chunk.id = GUINT32_FROM_LE (temp_chunk->id);
771 chunk.size = GUINT32_FROM_LE (temp_chunk->size);
774 case GST_RIFF_TAG_RIFF:
775 case GST_RIFF_TAG_LIST:
776 /* Read complete list chunk */
778 got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (gst_riff_list));
779 temp_chunk = (gst_riff_riff *) tempdata;
780 if (got_bytes < sizeof (gst_riff_list)) {
781 if (!gst_wavparse_handle_sink_event (wavparse)) {
789 chunk.type = GUINT32_FROM_LE (temp_chunk->type);
790 skipsize = sizeof (gst_riff_list);
793 case GST_RIFF_TAG_cue:
798 skipsize = sizeof (gst_riff_chunk);
801 gst_bytestream_flush (bs, skipsize);
804 /* need to flush an even number of bytes at the end */
805 flush = (chunk.size + 1) & ~1;
807 switch (wavparse->state) {
808 case GST_WAVPARSE_START:
809 if (chunk.id != GST_RIFF_TAG_RIFF &&
810 chunk.type != GST_RIFF_RIFF_WAVE) {
811 GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL),
812 ("chunk.id %08x chunk.type %08x", chunk.id, chunk.type));
816 wavparse->state = GST_WAVPARSE_OTHER;
817 /* We are not going to flush lists */
821 case GST_WAVPARSE_OTHER:
822 GST_DEBUG ("riff tag: %4.4s %08x", (char *) &chunk.id, chunk.size);
825 case GST_RIFF_TAG_data:
826 wavparse->state = GST_WAVPARSE_DATA;
827 wavparse->dataleft = chunk.size;
828 wavparse->byteoffset = 0;
832 case GST_RIFF_TAG_fmt:
833 gst_wavparse_parse_fmt (wavparse, chunk.size);
837 case GST_RIFF_TAG_cue:
838 //gst_wavparse_parse_cues (wavparse, chunk.size);
841 case GST_RIFF_TAG_LIST:
842 GST_DEBUG ("list type: %4.4s", (char *) &chunk.type);
843 switch (chunk.type) {
844 case GST_RIFF_LIST_INFO:
845 //gst_wavparse_parse_info (wavparse, chunk.size - 4);
850 case GST_RIFF_LIST_adtl:
851 //gst_wavparse_parse_adtl (wavparse, chunk.size - 4);
861 GST_DEBUG (" ***** unknown chunkid %08x", chunk.id);
867 case GST_WAVPARSE_DATA:
868 /* Should have been handled up there ^^^^ */
874 g_warning ("Unknown state %d\n", wavparse->state);
875 //GST_DEBUG (" ***** unknown chunkid %08x", chunk.id);
882 res = gst_bytestream_flush (bs, flush);
887 gst_bytestream_get_status (bs, &remaining, &event);
888 gst_event_unref (event);
893 /* convert and query stuff */
894 static const GstFormat *
895 gst_wavparse_get_formats (GstPad *pad)
897 static GstFormat formats[] = {
900 GST_FORMAT_DEFAULT, /* a "frame", ie a set of samples per Hz */
908 gst_wavparse_pad_convert (GstPad *pad,
909 GstFormat src_format, gint64 src_value,
910 GstFormat *dest_format, gint64 *dest_value)
912 gint bytes_per_sample;
914 GstWavParse *wavparse;
916 wavparse = GST_WAVPARSE (gst_pad_get_parent (pad));
918 bytes_per_sample = wavparse->channels * wavparse->width / 8;
919 if (bytes_per_sample == 0) {
920 GST_DEBUG ("bytes_per_sample is 0, probably an mp3 - channels %d, width %d\n",
921 wavparse->channels, wavparse->width);
924 byterate = (glong) (bytes_per_sample * wavparse->rate);
926 g_warning ("byterate is 0, internal error\n");
929 GST_DEBUG ("bytes per sample: %d\n", bytes_per_sample);
931 switch (src_format) {
932 case GST_FORMAT_BYTES:
933 if (*dest_format == GST_FORMAT_DEFAULT)
934 *dest_value = src_value / bytes_per_sample;
935 else if (*dest_format == GST_FORMAT_TIME)
936 *dest_value = src_value * GST_SECOND / byterate;
940 case GST_FORMAT_DEFAULT:
941 if (*dest_format == GST_FORMAT_BYTES)
942 *dest_value = src_value * bytes_per_sample;
943 else if (*dest_format == GST_FORMAT_TIME)
944 *dest_value = src_value * GST_SECOND / wavparse->rate;
948 case GST_FORMAT_TIME:
949 if (*dest_format == GST_FORMAT_BYTES)
950 *dest_value = src_value * byterate / GST_SECOND;
951 else if (*dest_format == GST_FORMAT_DEFAULT)
952 *dest_value = src_value * wavparse->rate / GST_SECOND;
956 *dest_value = *dest_value & ~(bytes_per_sample - 1);
959 g_warning ("unhandled format for wavparse\n");
965 static const GstQueryType *
966 gst_wavparse_get_query_types (GstPad *pad)
968 static const GstQueryType types[] = {
976 /* handle queries for location and length in requested format */
978 gst_wavparse_pad_query (GstPad *pad, GstQueryType type,
979 GstFormat *format, gint64 *value)
981 GstFormat peer_format = GST_FORMAT_BYTES;
983 GstWavParse *wavparse;
985 /* probe sink's peer pad, convert value, and that's it :) */
986 /* FIXME: ideally we'd loop over possible formats of peer instead
987 * of only using BYTE */
988 wavparse = GST_WAVPARSE (gst_pad_get_parent (pad));
989 if (!gst_pad_query (GST_PAD_PEER (wavparse->sinkpad), type,
990 &peer_format, &peer_value)) {
991 g_warning ("Could not query sink pad's peer\n");
994 if (!gst_pad_convert (wavparse->sinkpad, peer_format, peer_value,
996 g_warning ("Could not query sink pad's peer\n");
999 GST_DEBUG ("pad_query done, value %" G_GINT64_FORMAT "\n", *value);
1003 static const GstEventMask*
1004 gst_wavparse_get_event_masks (GstPad *pad)
1006 static const GstEventMask gst_wavparse_src_event_masks[] = {
1007 { GST_EVENT_SEEK, GST_SEEK_METHOD_SET |
1008 GST_SEEK_FLAG_FLUSH },
1011 return gst_wavparse_src_event_masks;
1015 gst_wavparse_srcpad_event (GstPad *pad, GstEvent *event)
1018 GstWavParse *wavparse = GST_WAVPARSE (GST_PAD_PARENT (pad));
1019 gboolean res = FALSE;
1021 GST_DEBUG ("event %d", GST_EVENT_TYPE (event));
1023 switch (GST_EVENT_TYPE (event)) {
1024 case GST_EVENT_SEEK:
1029 /* we can only seek when in the DATA state */
1030 if (wavparse->state != GST_WAVPARSE_DATA) {
1034 format = GST_FORMAT_BYTES;
1036 /* bring format to bytes for the peer element,
1037 * FIXME be smarter here */
1038 res = gst_pad_convert (pad,
1039 GST_EVENT_SEEK_FORMAT (event),
1040 GST_EVENT_SEEK_OFFSET (event),
1045 /* ok, seek worked, update our state */
1046 wavparse->seek_offset = byteoffset;
1047 wavparse->seek_pending = TRUE;
1048 wavparse->need_discont = TRUE;
1056 gst_event_unref (event);
1063 static GstElementStateReturn
1064 gst_wavparse_change_state (GstElement *element)
1066 GstWavParse *wavparse = GST_WAVPARSE (element);
1068 switch (GST_STATE_TRANSITION (element)) {
1069 case GST_STATE_NULL_TO_READY:
1071 case GST_STATE_READY_TO_PAUSED:
1072 wavparse->bs = gst_bytestream_new (wavparse->sinkpad);
1073 wavparse->state = GST_WAVPARSE_START;
1075 case GST_STATE_PAUSED_TO_PLAYING:
1077 case GST_STATE_PLAYING_TO_PAUSED:
1079 case GST_STATE_PAUSED_TO_READY:
1080 gst_bytestream_destroy (wavparse->bs);
1081 wavparse->state = GST_WAVPARSE_UNKNOWN;
1083 wavparse->seek_pending = FALSE;
1084 wavparse->seek_offset = 0;
1086 case GST_STATE_READY_TO_NULL:
1090 if (GST_ELEMENT_CLASS (parent_class)->change_state)
1091 return GST_ELEMENT_CLASS (parent_class)->change_state (element);
1093 return GST_STATE_SUCCESS;
1097 plugin_init (GstPlugin *plugin)
1099 if (!gst_library_load ("gstbytestream")) {
1103 return gst_element_register (plugin, "wavparse", GST_RANK_SECONDARY, GST_TYPE_WAVPARSE);
1110 "Parse a .wav file into raw audio",