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"
28 #include "gst/riff/riff-ids.h"
29 #include "gst/riff/riff-media.h"
31 GST_DEBUG_CATEGORY (wavparse_debug);
32 #define GST_CAT_DEFAULT (wavparse_debug)
34 static void gst_wavparse_base_init (gpointer g_class);
35 static void gst_wavparse_class_init (GstWavParseClass * klass);
36 static void gst_wavparse_init (GstWavParse * wavparse);
38 static GstElementStateReturn gst_wavparse_change_state (GstElement * element);
40 static const GstFormat *gst_wavparse_get_formats (GstPad * pad);
41 static const GstQueryType *gst_wavparse_get_query_types (GstPad * pad);
42 static gboolean gst_wavparse_pad_query (GstPad * pad,
43 GstQueryType type, GstFormat * format, gint64 * value);
44 static gboolean gst_wavparse_pad_convert (GstPad * pad,
46 gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
48 static void gst_wavparse_loop (GstElement * element);
49 static const GstEventMask *gst_wavparse_get_event_masks (GstPad * pad);
50 static gboolean gst_wavparse_srcpad_event (GstPad * pad, GstEvent * event);
51 static void gst_wavparse_get_property (GObject * object, guint prop_id,
52 GValue * value, GParamSpec * pspec);
54 static GstStaticPadTemplate sink_template_factory =
55 GST_STATIC_PAD_TEMPLATE ("wavparse_sink",
58 GST_STATIC_CAPS ("audio/x-wav")
61 static GstStaticPadTemplate src_template_factory =
62 GST_STATIC_PAD_TEMPLATE ("wavparse_src",
64 GST_PAD_SOMETIMES, /* FIXME: spider */
65 GST_STATIC_CAPS ("audio/x-raw-int, "
66 "endianness = (int) little_endian, "
67 "signed = (boolean) { true, false }, "
68 "width = (int) { 8, 16 }, "
69 "depth = (int) { 8, 16 }, "
70 "rate = (int) [ 8000, 48000 ], "
71 "channels = (int) [ 1, 2 ]; "
73 "mpegversion = (int) 1, "
74 "layer = (int) [ 1, 3 ], "
75 "rate = (int) [ 8000, 48000 ], "
76 "channels = (int) [ 1, 2 ]; "
78 "rate = (int) [ 8000, 48000 ], "
79 "channels = (int) [ 1, 2 ]; "
81 "rate = (int) [ 8000, 48000 ], " "channels = (int) [ 1, 2 ];"
83 "layout = (string) microsoft, "
84 "block_align = (int) [ 1, 8192 ], "
85 "rate = (int) [ 8000, 48000 ], "
86 "channels = (int) [ 1, 2 ]; "
88 "layout = (string) dvi, "
89 "block_align = (int) [ 1, 8192 ], "
90 "rate = (int) [ 8000, 48000 ], " "channels = (int) [ 1, 2 ]")
93 /* WavParse signals and args */
105 static GstElementClass *parent_class = NULL;
107 /*static guint gst_wavparse_signals[LAST_SIGNAL] = { 0 }; */
110 gst_wavparse_get_type (void)
112 static GType wavparse_type = 0;
114 if (!wavparse_type) {
115 static const GTypeInfo wavparse_info = {
116 sizeof (GstWavParseClass),
117 gst_wavparse_base_init,
119 (GClassInitFunc) gst_wavparse_class_init,
122 sizeof (GstWavParse),
124 (GInstanceInitFunc) gst_wavparse_init,
128 g_type_register_static (GST_TYPE_RIFF_READ, "GstWavParse",
131 return wavparse_type;
136 gst_wavparse_base_init (gpointer g_class)
138 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
139 static GstElementDetails gst_wavparse_details =
140 GST_ELEMENT_DETAILS (".wav demuxer",
141 "Codec/Demuxer/Audio",
142 "Parse a .wav file into raw audio",
143 "Erik Walthinsen <omega@cse.ogi.edu>");
145 gst_element_class_set_details (element_class, &gst_wavparse_details);
147 /* register src pads */
148 gst_element_class_add_pad_template (element_class,
149 gst_static_pad_template_get (&sink_template_factory));
150 gst_element_class_add_pad_template (element_class,
151 gst_static_pad_template_get (&src_template_factory));
155 gst_wavparse_class_init (GstWavParseClass * klass)
157 GstElementClass *gstelement_class;
158 GObjectClass *object_class;
160 gstelement_class = (GstElementClass *) klass;
161 object_class = (GObjectClass *) klass;
163 parent_class = g_type_class_ref (GST_TYPE_RIFF_READ);
165 object_class->get_property = gst_wavparse_get_property;
166 gstelement_class->change_state = gst_wavparse_change_state;
168 GST_DEBUG_CATEGORY_INIT (wavparse_debug, "wavparse", 0, "WAV parser");
172 gst_wavparse_init (GstWavParse * wavparse)
176 gst_pad_new_from_template (gst_static_pad_template_get
177 (&sink_template_factory), "sink");
178 gst_element_add_pad (GST_ELEMENT (wavparse), wavparse->sinkpad);
179 GST_RIFF_READ (wavparse)->sinkpad = wavparse->sinkpad;
181 gst_pad_set_formats_function (wavparse->sinkpad, gst_wavparse_get_formats);
182 gst_pad_set_convert_function (wavparse->sinkpad, gst_wavparse_pad_convert);
183 gst_pad_set_query_type_function (wavparse->sinkpad,
184 gst_wavparse_get_query_types);
185 gst_pad_set_query_function (wavparse->sinkpad, gst_wavparse_pad_query);
190 gst_pad_new_from_template (gst_static_pad_template_get
191 (&src_template_factory), "src");
192 gst_pad_use_explicit_caps (wavparse->srcpad);
193 gst_element_add_pad (GST_ELEMENT (wavparse), wavparse->srcpad);
194 gst_pad_set_formats_function (wavparse->srcpad, gst_wavparse_get_formats);
195 gst_pad_set_convert_function (wavparse->srcpad, gst_wavparse_pad_convert);
196 gst_pad_set_query_type_function (wavparse->srcpad,
197 gst_wavparse_get_query_types);
198 gst_pad_set_query_function (wavparse->srcpad, gst_wavparse_pad_query);
199 gst_pad_set_event_function (wavparse->srcpad, gst_wavparse_srcpad_event);
200 gst_pad_set_event_mask_function (wavparse->srcpad,
201 gst_wavparse_get_event_masks);
204 gst_element_set_loop_function (GST_ELEMENT (wavparse), gst_wavparse_loop);
206 wavparse->state = GST_WAVPARSE_START;
208 /* These will all be set correctly in the fmt chunk */
212 wavparse->channels = 0;
214 wavparse->seek_pending = FALSE;
215 wavparse->seek_offset = 0;
219 gst_wavparse_destroy_sourcepad (GstWavParse * wavparse)
221 if (wavparse->srcpad) {
222 gst_element_remove_pad (GST_ELEMENT (wavparse), wavparse->srcpad);
223 wavparse->srcpad = NULL;
228 gst_wavparse_create_sourcepad (GstWavParse * wavparse)
230 gst_wavparse_destroy_sourcepad (wavparse);
234 gst_pad_new_from_template (gst_static_pad_template_get
235 (&src_template_factory), "src");
236 gst_pad_use_explicit_caps (wavparse->srcpad);
237 gst_pad_set_formats_function (wavparse->srcpad, gst_wavparse_get_formats);
238 gst_pad_set_convert_function (wavparse->srcpad, gst_wavparse_pad_convert);
239 gst_pad_set_query_type_function (wavparse->srcpad,
240 gst_wavparse_get_query_types);
241 gst_pad_set_query_function (wavparse->srcpad, gst_wavparse_pad_query);
242 gst_pad_set_event_function (wavparse->srcpad, gst_wavparse_srcpad_event);
243 gst_pad_set_event_mask_function (wavparse->srcpad,
244 gst_wavparse_get_event_masks);
248 gst_wavparse_get_property (GObject * object,
249 guint prop_id, GValue * value, GParamSpec * pspec)
251 GstWavParse *wavparse;
253 wavparse = GST_WAVPARSE (object);
263 gst_wavparse_parse_adtl (GstWavParse * wavparse, int len)
266 GstByteStream *bs = wavparse->bs;
267 gst_riff_chunk *temp_chunk, chunk;
269 struct _gst_riff_labl labl, *temp_labl;
270 struct _gst_riff_ltxt ltxt, *temp_ltxt;
271 struct _gst_riff_note note, *temp_note;
274 GstPropsEntry *entry;
278 props = wavparse->metadata->properties;
282 gst_bytestream_peek_bytes (bs, &tempdata, sizeof (gst_riff_chunk));
283 if (got_bytes != sizeof (gst_riff_chunk)) {
286 temp_chunk = (gst_riff_chunk *) tempdata;
288 chunk.id = GUINT32_FROM_LE (temp_chunk->id);
289 chunk.size = GUINT32_FROM_LE (temp_chunk->size);
291 if (chunk.size == 0) {
292 gst_bytestream_flush (bs, sizeof (gst_riff_chunk));
293 len -= sizeof (gst_riff_chunk);
298 case GST_RIFF_adtl_labl:
300 gst_bytestream_peek_bytes (bs, &tempdata,
301 sizeof (struct _gst_riff_labl));
302 if (got_bytes != sizeof (struct _gst_riff_labl)) {
306 temp_labl = (struct _gst_riff_labl *) tempdata;
307 labl.id = GUINT32_FROM_LE (temp_labl->id);
308 labl.size = GUINT32_FROM_LE (temp_labl->size);
309 labl.identifier = GUINT32_FROM_LE (temp_labl->identifier);
311 gst_bytestream_flush (bs, sizeof (struct _gst_riff_labl));
312 len -= sizeof (struct _gst_riff_labl);
314 got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, labl.size - 4);
315 if (got_bytes != labl.size - 4) {
319 label_name = (char *) tempdata;
321 gst_bytestream_flush (bs, ((labl.size - 4) + 1) & ~1);
322 len -= (((labl.size - 4) + 1) & ~1);
324 new_caps = gst_caps_new ("label",
325 "application/x-gst-metadata",
326 gst_props_new ("identifier", G_TYPE_INT (labl.identifier),
327 "name", G_TYPE_STRING (label_name), NULL));
329 if (gst_props_get (props, "labels", &caps, NULL)) {
330 caps = g_list_append (caps, new_caps);
332 caps = g_list_append (NULL, new_caps);
334 entry = gst_props_entry_new ("labels", GST_PROPS_GLIST (caps));
335 gst_props_add_entry (props, entry);
340 case GST_RIFF_adtl_ltxt:
342 gst_bytestream_peek_bytes (bs, &tempdata,
343 sizeof (struct _gst_riff_ltxt));
344 if (got_bytes != sizeof (struct _gst_riff_ltxt)) {
348 temp_ltxt = (struct _gst_riff_ltxt *) tempdata;
349 ltxt.id = GUINT32_FROM_LE (temp_ltxt->id);
350 ltxt.size = GUINT32_FROM_LE (temp_ltxt->size);
351 ltxt.identifier = GUINT32_FROM_LE (temp_ltxt->identifier);
352 ltxt.length = GUINT32_FROM_LE (temp_ltxt->length);
353 ltxt.purpose = GUINT32_FROM_LE (temp_ltxt->purpose);
354 ltxt.country = GUINT16_FROM_LE (temp_ltxt->country);
355 ltxt.language = GUINT16_FROM_LE (temp_ltxt->language);
356 ltxt.dialect = GUINT16_FROM_LE (temp_ltxt->dialect);
357 ltxt.codepage = GUINT16_FROM_LE (temp_ltxt->codepage);
359 gst_bytestream_flush (bs, sizeof (struct _gst_riff_ltxt));
360 len -= sizeof (struct _gst_riff_ltxt);
362 if (ltxt.size - 20 > 0) {
363 got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, ltxt.size - 20);
364 if (got_bytes != ltxt.size - 20) {
368 gst_bytestream_flush (bs, ((ltxt.size - 20) + 1) & ~1);
369 len -= (((ltxt.size - 20) + 1) & ~1);
371 label_name = (char *) tempdata;
376 new_caps = gst_caps_new ("ltxt",
377 "application/x-gst-metadata",
378 gst_props_new ("identifier", G_TYPE_INT (ltxt.identifier),
379 "name", G_TYPE_STRING (label_name),
380 "length", G_TYPE_INT (ltxt.length), NULL));
382 if (gst_props_get (props, "ltxts", &caps, NULL)) {
383 caps = g_list_append (caps, new_caps);
385 caps = g_list_append (NULL, new_caps);
387 entry = gst_props_entry_new ("ltxts", GST_PROPS_GLIST (caps));
388 gst_props_add_entry (props, entry);
393 case GST_RIFF_adtl_note:
395 gst_bytestream_peek_bytes (bs, &tempdata,
396 sizeof (struct _gst_riff_note));
397 if (got_bytes != sizeof (struct _gst_riff_note)) {
401 temp_note = (struct _gst_riff_note *) tempdata;
402 note.id = GUINT32_FROM_LE (temp_note->id);
403 note.size = GUINT32_FROM_LE (temp_note->size);
404 note.identifier = GUINT32_FROM_LE (temp_note->identifier);
406 gst_bytestream_flush (bs, sizeof (struct _gst_riff_note));
407 len -= sizeof (struct _gst_riff_note);
409 got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, note.size - 4);
410 if (got_bytes != note.size - 4) {
414 gst_bytestream_flush (bs, ((note.size - 4) + 1) & ~1);
415 len -= (((note.size - 4) + 1) & ~1);
417 label_name = (char *) tempdata;
419 new_caps = gst_caps_new ("note",
420 "application/x-gst-metadata",
421 gst_props_new ("identifier", G_TYPE_INT (note.identifier),
422 "name", G_TYPE_STRING (label_name), NULL));
424 if (gst_props_get (props, "notes", &caps, NULL)) {
425 caps = g_list_append (caps, new_caps);
427 caps = g_list_append (NULL, new_caps);
429 entry = gst_props_entry_new ("notes", GST_PROPS_GLIST (caps));
430 gst_props_add_entry (props, entry);
436 g_print ("Unknown chunk: " GST_FOURCC_FORMAT "\n",
437 GST_FOURCC_ARGS (chunk.id));
442 g_object_notify (G_OBJECT (wavparse), "metadata");
448 gst_wavparse_parse_cues (GstWavParse * wavparse, int len)
451 GstByteStream *bs = wavparse->bs;
452 struct _gst_riff_cue *temp_cue, cue;
453 struct _gst_riff_cuepoints *points;
457 GstPropsEntry *entry;
463 gst_bytestream_peek_bytes (bs, &tempdata,
464 sizeof (struct _gst_riff_cue));
465 temp_cue = (struct _gst_riff_cue *) tempdata;
467 /* fixup for our big endian friends */
468 cue.id = GUINT32_FROM_LE (temp_cue->id);
469 cue.size = GUINT32_FROM_LE (temp_cue->size);
470 cue.cuepoints = GUINT32_FROM_LE (temp_cue->cuepoints);
472 gst_bytestream_flush (bs, sizeof (struct _gst_riff_cue));
473 if (got_bytes != sizeof (struct _gst_riff_cue)) {
477 len -= sizeof (struct _gst_riff_cue);
479 /* -4 because cue.size contains the cuepoints size
480 and we've already flushed that out of the system */
481 required = cue.size - 4;
482 got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, required);
483 gst_bytestream_flush (bs, ((required) + 1) & ~1);
484 if (got_bytes != required) {
488 len -= (((cue.size - 4) + 1) & ~1);
490 /* now we have an array of struct _gst_riff_cuepoints in tempdata */
491 points = (struct _gst_riff_cuepoints *) tempdata;
493 for (i = 0; i < cue.cuepoints; i++) {
496 caps = gst_caps_new ("cues",
497 "application/x-gst-metadata",
498 gst_props_new ("identifier", G_TYPE_INT (points[i].identifier),
499 "position", G_TYPE_INT (points[i].offset), NULL));
500 cues = g_list_append (cues, caps);
503 entry = gst_props_entry_new ("cues", GST_PROPS_GLIST (cues));
504 gst_props_add_entry (wavparse->metadata->properties, entry);
507 g_object_notify (G_OBJECT (wavparse), "metadata");
512 gst_wavparse_stream_init (GstWavParse * wav)
514 GstRiffRead *riff = GST_RIFF_READ (wav);
517 if (!gst_riff_read_header (riff, &doctype)) {
518 GST_WARNING_OBJECT (wav, "could not read header");
522 if (doctype != GST_RIFF_RIFF_WAVE) {
523 GST_ELEMENT_ERROR (wav, STREAM, WRONG_TYPE, (NULL), (NULL));
530 /* Read 'fmt ' header */
532 gst_wavparse_fmt (GstWavParse * wav)
534 GstRiffRead *riff = GST_RIFF_READ (wav);
535 gst_riff_strf_auds *header = NULL;
538 if (!gst_riff_read_strf_auds (riff, &header)) {
539 g_warning ("Not fmt");
543 wav->format = header->format;
544 wav->rate = header->rate;
545 wav->channels = header->channels;
546 wav->blockalign = header->blockalign;
547 wav->width = (header->blockalign * 8) / header->channels;
548 wav->depth = header->size;
549 wav->bps = header->av_bps;
551 caps = gst_riff_create_audio_caps (header->format, NULL, header, NULL);
554 gst_wavparse_create_sourcepad (wav);
555 gst_pad_set_explicit_caps (wav->srcpad, caps);
556 gst_caps_free (caps);
557 gst_element_add_pad (GST_ELEMENT (wav), wav->srcpad);
558 GST_DEBUG ("frequency %d, channels %d", wav->rate, wav->channels);
560 GST_ELEMENT_ERROR (wav, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
572 gst_wavparse_other (GstWavParse * wav)
574 GstRiffRead *riff = GST_RIFF_READ (wav);
577 if (!gst_riff_peek_head (riff, &tag, &length, NULL)) {
578 GST_WARNING_OBJECT (wav, "could not peek head");
581 GST_DEBUG_OBJECT (wav, "got tag (%08x) %4.4s, length %d", tag,
582 (gchar *) & tag, length);
585 case GST_RIFF_TAG_LIST:
586 if (!(tag = gst_riff_peek_list (riff))) {
587 GST_WARNING_OBJECT (wav, "could not peek list");
592 case GST_RIFF_LIST_INFO:
593 if (!gst_riff_read_list (riff, &tag) || !gst_riff_read_info (riff)) {
594 GST_WARNING_OBJECT (wav, "could not read list");
599 case GST_RIFF_LIST_adtl:
600 if (!gst_riff_read_skip (riff)) {
601 GST_WARNING_OBJECT (wav, "could not read skip");
607 GST_DEBUG_OBJECT (wav, "skipping tag (%08x) %4.4s", tag,
609 if (!gst_riff_read_skip (riff)) {
610 GST_WARNING_OBJECT (wav, "could not read skip");
618 case GST_RIFF_TAG_data:
619 if (!gst_bytestream_flush (riff->bs, 8)) {
620 GST_WARNING_OBJECT (wav, "could not flush 8 bytes");
624 GST_DEBUG_OBJECT (wav, "switching to data mode");
625 wav->state = GST_WAVPARSE_DATA;
626 wav->datastart = gst_bytestream_tell (riff->bs);
630 /* length is 0, data probably stretches to the end
632 GST_DEBUG_OBJECT (wav, "length is 0 trying to find length");
633 /* get length of file */
634 file_length = gst_bytestream_length (riff->bs);
635 if (file_length == -1) {
636 GST_DEBUG_OBJECT (wav,
637 "could not get file length, assuming data to eof");
638 /* could not get length, assuming till eof */
639 length = G_MAXUINT32;
641 if (file_length > G_MAXUINT32) {
642 GST_DEBUG_OBJECT (wav, "file length %lld, clipping to 32 bits");
643 /* could not get length, assuming till eof */
644 length = G_MAXUINT32;
646 GST_DEBUG_OBJECT (wav, "file length %lld, datalength", file_length,
648 /* substract offset of datastart from length */
649 length = file_length - wav->datastart;
650 GST_DEBUG_OBJECT (wav, "datalength %lld", length);
653 wav->dataleft = wav->datasize = (guint64) length;
656 case GST_RIFF_TAG_cue:
657 if (!gst_riff_read_skip (riff)) {
658 GST_WARNING_OBJECT (wav, "could not read skip");
664 GST_DEBUG_OBJECT (wav, "skipping tag (%08x) %4.4s", tag, (gchar *) & tag);
665 if (!gst_riff_read_skip (riff))
674 gst_wavparse_handle_seek (GstWavParse * wav)
676 GstRiffRead *riff = GST_RIFF_READ (wav);
677 GstEvent *event = NULL;
681 if (!gst_bytestream_seek (riff->bs, wav->seek_offset + wav->datastart,
682 GST_SEEK_METHOD_SET))
685 /* wait for discont */
687 if (gst_bytestream_peek_bytes (riff->bs, &data, 1)) {
688 GST_WARNING ("Unexpected data after seek - this means seek failed");
692 /* get the discont event and return */
693 gst_bytestream_get_status (riff->bs, &remaining, &event);
695 GST_WARNING ("No discontinuity event after seek - seek failed");
697 } else if (GST_EVENT_TYPE (event) != GST_EVENT_DISCONTINUOUS) {
698 GstEventType type = GST_EVENT_TYPE (event);
700 gst_pad_event_default (riff->sinkpad, event);
701 if (type == GST_EVENT_EOS)
708 wav->dataleft = wav->datasize - wav->seek_offset;
710 gst_event_unref (event);
711 event = gst_event_new_discontinuous (FALSE,
712 GST_FORMAT_BYTES, wav->seek_offset,
713 GST_FORMAT_TIME, GST_SECOND * wav->seek_offset / wav->bps,
714 GST_FORMAT_UNDEFINED);
715 gst_pad_event_default (wav->sinkpad, event);
720 #define MAX_BUFFER_SIZE 4096
723 gst_wavparse_loop (GstElement * element)
725 GstWavParse *wav = GST_WAVPARSE (element);
726 GstRiffRead *riff = GST_RIFF_READ (wav);
728 if (wav->state == GST_WAVPARSE_DATA) {
730 if (wav->seek_pending) {
731 gst_wavparse_handle_seek (wav);
732 wav->seek_pending = FALSE;
735 if (wav->dataleft > 0) {
736 guint32 got_bytes, desired;
737 GstBuffer *buf = NULL;
739 desired = MIN (wav->dataleft, MAX_BUFFER_SIZE);
740 if (!(buf = gst_riff_read_element_data (riff, desired, &got_bytes))) {
741 GST_WARNING_OBJECT (wav, "trying to read %d bytes failed", desired);
744 GST_DEBUG_OBJECT (wav, "read %d bytes, got %d bytes", desired, got_bytes);
746 GST_BUFFER_TIMESTAMP (buf) = GST_SECOND *
747 (wav->datasize - wav->dataleft) / wav->bps;
748 GST_BUFFER_DURATION (buf) = GST_SECOND * got_bytes / wav->bps;
750 gst_pad_push (wav->srcpad, GST_DATA (buf));
752 wav->byteoffset += got_bytes;
753 if (got_bytes < wav->dataleft) {
754 wav->dataleft -= got_bytes;
758 wav->state = GST_WAVPARSE_OTHER;
761 wav->state = GST_WAVPARSE_OTHER;
765 switch (wav->state) {
766 case GST_WAVPARSE_START:
767 if (!gst_wavparse_stream_init (wav)) {
771 wav->state = GST_WAVPARSE_FMT;
774 case GST_WAVPARSE_FMT:
775 if (!gst_wavparse_fmt (wav)) {
779 wav->state = GST_WAVPARSE_OTHER;
782 case GST_WAVPARSE_OTHER:
783 if (!gst_wavparse_other (wav)) {
789 case GST_WAVPARSE_DATA:
792 g_assert_not_reached ();
796 /* convert and query stuff */
797 static const GstFormat *
798 gst_wavparse_get_formats (GstPad * pad)
800 static GstFormat formats[] = {
803 GST_FORMAT_DEFAULT, /* a "frame", ie a set of samples per Hz */
811 gst_wavparse_pad_convert (GstPad * pad,
812 GstFormat src_format, gint64 src_value,
813 GstFormat * dest_format, gint64 * dest_value)
815 guint bytes_per_sample, byterate;
816 GstWavParse *wavparse;
818 wavparse = GST_WAVPARSE (gst_pad_get_parent (pad));
820 bytes_per_sample = wavparse->channels * wavparse->width / 8;
821 if (bytes_per_sample == 0) {
822 GST_DEBUG ("bytes_per_sample 0, probably an mp3 - channels %d, width %d",
823 wavparse->channels, wavparse->width);
826 byterate = wavparse->bps;
828 g_warning ("byterate is 0, internal error\n");
831 GST_DEBUG ("bytes per sample: %d", bytes_per_sample);
833 switch (src_format) {
834 case GST_FORMAT_BYTES:
835 switch (*dest_format) {
836 case GST_FORMAT_DEFAULT:
837 *dest_value = src_value / bytes_per_sample;
839 case GST_FORMAT_TIME:
840 *dest_value = src_value * GST_SECOND / byterate;
845 *dest_value -= *dest_value % bytes_per_sample;
848 case GST_FORMAT_DEFAULT:
849 switch (*dest_format) {
850 case GST_FORMAT_BYTES:
851 *dest_value = src_value * bytes_per_sample;
853 case GST_FORMAT_TIME:
854 *dest_value = src_value * GST_SECOND / wavparse->rate;
861 case GST_FORMAT_TIME:
862 switch (*dest_format) {
863 case GST_FORMAT_BYTES:
864 /* make sure we end up on a sample boundary */
866 (src_value * wavparse->rate / GST_SECOND) * wavparse->blockalign;
868 case GST_FORMAT_DEFAULT:
869 *dest_value = src_value * wavparse->rate / GST_SECOND;
883 static const GstQueryType *
884 gst_wavparse_get_query_types (GstPad * pad)
886 static const GstQueryType types[] = {
895 /* handle queries for location and length in requested format */
897 gst_wavparse_pad_query (GstPad * pad, GstQueryType type,
898 GstFormat * format, gint64 * value)
901 GstWavParse *wav = GST_WAVPARSE (gst_pad_get_parent (pad));
903 /* only if we know */
904 if (wav->state != GST_WAVPARSE_DATA)
908 case GST_QUERY_POSITION:
909 bytevalue = wav->datasize - wav->dataleft;
911 case GST_QUERY_TOTAL:
912 bytevalue = wav->datasize;
918 if (*format == GST_FORMAT_BYTES) {
923 return gst_pad_convert (wav->sinkpad, GST_FORMAT_BYTES,
924 bytevalue, format, value);
927 static const GstEventMask *
928 gst_wavparse_get_event_masks (GstPad * pad)
930 static const GstEventMask gst_wavparse_src_event_masks[] = {
931 {GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH},
935 return gst_wavparse_src_event_masks;
939 gst_wavparse_srcpad_event (GstPad * pad, GstEvent * event)
941 GstWavParse *wavparse = GST_WAVPARSE (GST_PAD_PARENT (pad));
942 gboolean res = FALSE;
944 GST_DEBUG ("event %d", GST_EVENT_TYPE (event));
946 switch (GST_EVENT_TYPE (event)) {
952 /* bring format to samples for the peer element, */
953 format = GST_FORMAT_BYTES;
954 res = gst_pad_convert (pad,
955 GST_EVENT_SEEK_FORMAT (event),
956 GST_EVENT_SEEK_OFFSET (event), &format, &byteoffset);
959 /* ok, seek worked, update our state */
960 wavparse->seek_offset = byteoffset;
961 wavparse->seek_pending = TRUE;
969 gst_event_unref (event);
974 static GstElementStateReturn
975 gst_wavparse_change_state (GstElement * element)
977 GstWavParse *wav = GST_WAVPARSE (element);
979 switch (GST_STATE_TRANSITION (element)) {
980 case GST_STATE_NULL_TO_READY:
983 case GST_STATE_READY_TO_PAUSED:
984 wav->state = GST_WAVPARSE_START;
987 case GST_STATE_PAUSED_TO_PLAYING:
990 case GST_STATE_PLAYING_TO_PAUSED:
993 case GST_STATE_PAUSED_TO_READY:
994 gst_wavparse_destroy_sourcepad (wav);
995 wav->state = GST_WAVPARSE_START;
1002 wav->seek_pending = FALSE;
1003 wav->seek_offset = 0;
1006 case GST_STATE_READY_TO_NULL:
1010 if (GST_ELEMENT_CLASS (parent_class)->change_state)
1011 return GST_ELEMENT_CLASS (parent_class)->change_state (element);
1013 return GST_STATE_SUCCESS;
1017 plugin_init (GstPlugin * plugin)
1019 if (!gst_library_load ("riff")) {
1023 return gst_element_register (plugin, "wavparse", GST_RANK_PRIMARY,
1027 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1030 "Parse a .wav file into raw audio",
1031 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN)