From f868ebb4bcbeee46ff5ef359fe3b655f3a3f5b0e Mon Sep 17 00:00:00 2001 From: Iain Holmes Date: Sat, 8 May 2004 00:33:39 +0000 Subject: [PATCH] Rewrote wavparse to use riff-read instead of doing bytestream stuff by hand. Original commit message from CVS: Rewrote wavparse to use riff-read instead of doing bytestream stuff by hand. Made some useful functions in riff-read non-static. --- ChangeLog | 8 + gst/wavparse/gstwavparse.c | 434 +++++++++++++++++---------------------------- gst/wavparse/gstwavparse.h | 36 ++-- 3 files changed, 182 insertions(+), 296 deletions(-) diff --git a/ChangeLog b/ChangeLog index f68af3f..20809c5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2004-05-08 Iain + + * gst/wavparse/gstwavparse.[ch]: Rewrote to use RiffRead instead. + * gst-libs/gst/riff/riff-read.c (gst_riff_read_peek_head): Unstatic it + (gst_riff_read_element_data): Ditto, and added a got_bytes argument to + return the length that was read. + (gst_riff_read_strf_auds): Allow fmt tags as well. + 2004-05-07 David Schleef * ext/faad/gstfaad.c: (gst_faad_sinkconnect): HACK to correct diff --git a/gst/wavparse/gstwavparse.c b/gst/wavparse/gstwavparse.c index dc34eed..0e90130 100644 --- a/gst/wavparse/gstwavparse.c +++ b/gst/wavparse/gstwavparse.c @@ -25,6 +25,8 @@ #include #include +#include "gst/riff/riff-ids.h" +#include "gst/riff/riff-media.h" static void gst_wavparse_base_init (gpointer g_class); static void gst_wavparse_class_init (GstWavParseClass * klass); @@ -127,8 +129,8 @@ gst_wavparse_get_type (void) }; wavparse_type = - g_type_register_static (GST_TYPE_ELEMENT, "GstWavParse", &wavparse_info, - 0); + g_type_register_static (GST_TYPE_RIFF_READ, "GstWavParse", + &wavparse_info, 0); } return wavparse_type; } @@ -147,6 +149,7 @@ gst_wavparse_base_init (gpointer g_class) gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&src_template_factory)); } + static void gst_wavparse_class_init (GstWavParseClass * klass) { @@ -156,7 +159,7 @@ gst_wavparse_class_init (GstWavParseClass * klass) gstelement_class = (GstElementClass *) klass; object_class = (GObjectClass *) klass; - parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + parent_class = g_type_class_ref (GST_TYPE_RIFF_READ); object_class->get_property = gst_wavparse_get_property; gstelement_class->change_state = gst_wavparse_change_state; @@ -170,12 +173,14 @@ gst_wavparse_init (GstWavParse * wavparse) gst_pad_new_from_template (gst_static_pad_template_get (&sink_template_factory), "sink"); gst_element_add_pad (GST_ELEMENT (wavparse), wavparse->sinkpad); + GST_RIFF_READ (wavparse)->sinkpad = wavparse->sinkpad; gst_pad_set_formats_function (wavparse->sinkpad, gst_wavparse_get_formats); gst_pad_set_convert_function (wavparse->sinkpad, gst_wavparse_pad_convert); gst_pad_set_query_type_function (wavparse->sinkpad, gst_wavparse_get_query_types); gst_pad_set_query_function (wavparse->sinkpad, gst_wavparse_pad_query); + #if 0 /* source */ wavparse->srcpad = @@ -192,10 +197,17 @@ gst_wavparse_init (GstWavParse * wavparse) gst_pad_set_event_mask_function (wavparse->srcpad, gst_wavparse_get_event_masks); #endif + gst_element_set_loop_function (GST_ELEMENT (wavparse), gst_wavparse_loop); - wavparse->state = GST_WAVPARSE_UNKNOWN; - wavparse->bps = 0; + wavparse->state = GST_WAVPARSE_START; + + /* These will all be set correctly in the fmt chunk */ + wavparse->depth = 0; + wavparse->rate = 0; + wavparse->width = 0; + wavparse->channels = 0; + wavparse->seek_pending = FALSE; wavparse->seek_offset = 0; } @@ -218,8 +230,6 @@ gst_wavparse_create_sourcepad (GstWavParse * wavparse) gst_pad_new_from_template (gst_static_pad_template_get (&src_template_factory), "src"); gst_pad_use_explicit_caps (wavparse->srcpad); - /*gst_element_add_pad (GST_ELEMENT (wavparse), wavparse->srcpad); */ - /*gst_element_add_pad (GST_ELEMENT (wavparse), wavparse->srcpad); */ gst_pad_set_formats_function (wavparse->srcpad, gst_wavparse_get_formats); gst_pad_set_convert_function (wavparse->srcpad, gst_wavparse_pad_convert); gst_pad_set_query_type_function (wavparse->srcpad, @@ -611,101 +621,7 @@ gst_wavparse_parse_cues (GstWavParse * wavparse, int len) } #endif -static void -gst_wavparse_parse_fmt (GstWavParse * wavparse, guint size) -{ - GstWavParseFormat *format; - GstCaps *caps = NULL; - guint8 *fmtdata; - GstByteStream *bs = wavparse->bs; - guint32 got_bytes; - - got_bytes = - gst_bytestream_peek_bytes (bs, &fmtdata, sizeof (GstWavParseFormat)); - format = (GstWavParseFormat *) fmtdata; - - if (got_bytes == sizeof (GstWavParseFormat)) { - gst_bytestream_flush (bs, size); - wavparse->bps = GUINT16_FROM_LE (format->wBlockAlign); - wavparse->rate = GUINT32_FROM_LE (format->dwSamplesPerSec); - wavparse->channels = GUINT16_FROM_LE (format->wChannels); - wavparse->width = GUINT16_FROM_LE (format->wBitsPerSample); - wavparse->format = GINT16_FROM_LE (format->wFormatTag); - - gst_wavparse_create_sourcepad (wavparse); - - /* set the caps on the src pad */ - /* FIXME: handle all of the other formats as well */ - switch (wavparse->format) { - case GST_RIFF_WAVE_FORMAT_ALAW: - case GST_RIFF_WAVE_FORMAT_MULAW:{ - char *mime = (wavparse->format == GST_RIFF_WAVE_FORMAT_ALAW) ? - "audio/x-alaw" : "audio/x-mulaw"; - if (wavparse->width != 8) { - g_warning ("Ignoring invalid width %d", wavparse->width); - return; - } - - caps = gst_caps_new_simple (mime, - "rate", G_TYPE_INT, wavparse->rate, - "channels", G_TYPE_INT, wavparse->channels, NULL); - } - break; - - case GST_RIFF_WAVE_FORMAT_PCM: - caps = gst_caps_new_simple ("audio/x-raw-int", - "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, - "signed", G_TYPE_BOOLEAN, (wavparse->width > 8) ? TRUE : FALSE, - "width", G_TYPE_INT, wavparse->width, - "depth", G_TYPE_INT, wavparse->width, - "rate", G_TYPE_INT, wavparse->rate, - "channels", G_TYPE_INT, wavparse->channels, NULL); - break; - - case GST_RIFF_WAVE_FORMAT_ADPCM: - caps = gst_caps_new_simple ("audio/x-adpcm", - "layout", G_TYPE_STRING, "microsoft", - "block_align", G_TYPE_INT, wavparse->bps, - "rate", G_TYPE_INT, wavparse->rate, - "channels", G_TYPE_INT, wavparse->channels, NULL); - break; - - case GST_RIFF_WAVE_FORMAT_DVI_ADPCM: - caps = gst_caps_new_simple ("audio/x-adpcm", - "layout", G_TYPE_STRING, "dvi", - "block_align", G_TYPE_INT, wavparse->bps, - "rate", G_TYPE_INT, wavparse->rate, - "channels", G_TYPE_INT, wavparse->channels, NULL); - break; - - case GST_RIFF_WAVE_FORMAT_MPEGL12: - case GST_RIFF_WAVE_FORMAT_MPEGL3:{ - int layer = (wavparse->format == GST_RIFF_WAVE_FORMAT_MPEGL12) ? 2 : 3; - - caps = gst_caps_new_simple ("audio/mpeg", - "mpegversion", G_TYPE_INT, 1, - "layer", G_TYPE_INT, layer, - "rate", G_TYPE_INT, wavparse->rate, - "channels", G_TYPE_INT, wavparse->channels, NULL); - } - break; - - default: - GST_ELEMENT_ERROR (wavparse, STREAM, NOT_IMPLEMENTED, (NULL), - ("format %d not handled", wavparse->format)); - return; - } - - if (caps) { - gst_pad_set_explicit_caps (wavparse->srcpad, caps); - gst_caps_free (caps); - } - gst_element_add_pad (GST_ELEMENT (wavparse), wavparse->srcpad); - - GST_DEBUG ("frequency %d, channels %d", wavparse->rate, wavparse->channels); - } -} - +#if 0 static gboolean gst_wavparse_handle_sink_event (GstWavParse * wavparse) { @@ -741,214 +657,172 @@ gst_wavparse_handle_sink_event (GstWavParse * wavparse) done: return res; } +#endif -static void -gst_wavparse_loop (GstElement * element) +static gboolean +gst_wavparse_stream_init (GstWavParse * wav) { - GstWavParse *wavparse; - gst_riff_riff chunk; - guint32 flush = 0; - guint32 got_bytes; - GstByteStream *bs; + GstRiffRead *riff = GST_RIFF_READ (wav); + guint32 doctype; - wavparse = GST_WAVPARSE (element); + if (!gst_riff_read_header (riff, &doctype)) + return FALSE; - bs = wavparse->bs; + if (doctype != GST_RIFF_RIFF_WAVE) { + GST_ELEMENT_ERROR (wav, STREAM, WRONG_TYPE, (NULL), (NULL)); + return FALSE; + } - if (wavparse->seek_pending) { - GST_DEBUG ("wavparse: seek pending to %" G_GINT64_FORMAT " %08llx", - wavparse->seek_offset, (unsigned long long) wavparse->seek_offset); + return TRUE; +} - if (!gst_bytestream_seek (bs, wavparse->seek_offset, GST_SEEK_METHOD_SET)) { - GST_INFO ("wavparse: Could not seek"); - } +/* Read 'fmt ' header */ +static gboolean +gst_wavparse_fmt (GstWavParse * wav) +{ + GstRiffRead *riff = GST_RIFF_READ (wav); + gst_riff_strf_auds *header; + GstCaps *caps; - wavparse->seek_pending = FALSE; + if (!gst_riff_read_strf_auds (riff, &header)) { + g_warning ("Not fmt"); + return FALSE; } - if (wavparse->state == GST_WAVPARSE_DATA) { - GstBuffer *buf; - int desired; + gst_wavparse_create_sourcepad (wav); - /* This seems to want the whole chunk, - Will this screw up streaming? - Does anyone care about streaming wavs? - FIXME: Should we have a decent buffer size? */ + wav->format = header->format; + wav->rate = header->rate; + wav->channels = header->channels; + wav->width = (header->blockalign * 8) / header->channels; + wav->depth = header->size; -#define MAX_BUFFER_SIZE 4096 + caps = gst_riff_create_audio_caps (header->format, NULL, header, NULL); - if (wavparse->dataleft > 0) { - desired = MIN (wavparse->dataleft, MAX_BUFFER_SIZE); - got_bytes = gst_bytestream_peek (bs, &buf, desired); + if (caps) { + gst_pad_set_explicit_caps (wav->srcpad, caps); + gst_caps_free (caps); + } + gst_element_add_pad (GST_ELEMENT (wav), wav->srcpad); - if (got_bytes != desired) { - /* EOS? */ - GstEvent *event; - guint32 remaining; + GST_DEBUG ("frequency %d, channels %d", wav->rate, wav->channels); - gst_bytestream_get_status (bs, &remaining, &event); - if (event) { - gst_pad_event_default (wavparse->sinkpad, event); - } else { - GST_ELEMENT_ERROR (element, RESOURCE, READ, (NULL), (NULL)); - } - return; - } + return TRUE; +} - wavparse->dataleft -= got_bytes; - wavparse->byteoffset += got_bytes; +static gboolean +gst_wavparse_other (GstWavParse * wav) +{ + GstRiffRead *riff = GST_RIFF_READ (wav); + guint32 tag, length; - gst_bytestream_flush (bs, got_bytes); + /* Fixme, need to handle a seek...can you seek in wavs? */ - gst_pad_push (wavparse->srcpad, GST_DATA (buf)); - return; - } else { - wavparse->state = GST_WAVPARSE_OTHER; - } + if (!gst_riff_peek_head (riff, &tag, &length, NULL)) { + return FALSE; } - do { - gst_riff_riff *temp_chunk; - guint8 *tempdata; - guint32 skipsize; + switch (tag) { + case GST_RIFF_TAG_LIST: + if (!(tag = gst_riff_peek_list (riff))) { + return FALSE; + } - /* read first two dwords to get chunktype and size */ - while (TRUE) { - got_bytes = - gst_bytestream_peek_bytes (bs, &tempdata, sizeof (gst_riff_chunk)); - temp_chunk = (gst_riff_riff *) tempdata; + switch (tag) { + case GST_RIFF_LIST_INFO: + gst_riff_read_skip (riff); + break; - if (got_bytes < sizeof (gst_riff_chunk)) { - if (!gst_wavparse_handle_sink_event (wavparse)) { - return; - } - } else { - break; + case GST_RIFF_LIST_adtl: + gst_riff_read_skip (riff); + break; + + default: + gst_riff_read_skip (riff); + break; } - } - chunk.id = GUINT32_FROM_LE (temp_chunk->id); - chunk.size = GUINT32_FROM_LE (temp_chunk->size); + break; - switch (chunk.id) { - case GST_RIFF_TAG_RIFF: - case GST_RIFF_TAG_LIST: - /* Read complete list chunk */ - while (TRUE) { - got_bytes = - gst_bytestream_peek_bytes (bs, &tempdata, sizeof (gst_riff_list)); - temp_chunk = (gst_riff_riff *) tempdata; - if (got_bytes < sizeof (gst_riff_list)) { - if (!gst_wavparse_handle_sink_event (wavparse)) { - return; - } - } else { - break; - } - } + case GST_RIFF_TAG_data: + gst_bytestream_flush (riff->bs, 8); - chunk.type = GUINT32_FROM_LE (temp_chunk->type); - skipsize = sizeof (gst_riff_list); - chunk.size -= 4; /* size is including list type, which we flush */ - break; + wav->state = GST_WAVPARSE_DATA; + wav->dataleft = (guint64) length; + break; - case GST_RIFF_TAG_cue: - skipsize = 0; - break; + case GST_RIFF_TAG_cue: + gst_riff_read_skip (riff); + break; - default: - skipsize = sizeof (gst_riff_chunk); - break; - } - gst_bytestream_flush (bs, skipsize); - } while (FALSE); + default: + gst_riff_read_skip (riff); + break; + } - /* need to flush an even number of bytes at the end */ - flush = (chunk.size + 1) & ~1; + return TRUE; +} - switch (wavparse->state) { - case GST_WAVPARSE_START: - if (chunk.id != GST_RIFF_TAG_RIFF && chunk.type != GST_RIFF_RIFF_WAVE) { - GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL), - ("chunk.id %08x chunk.type %08x", chunk.id, chunk.type)); - return; - } +#define MAX_BUFFER_SIZE 4096 - wavparse->state = GST_WAVPARSE_OTHER; - /* We are not going to flush lists */ - flush = 0; - break; +static void +gst_wavparse_loop (GstElement * element) +{ + GstWavParse *wav = GST_WAVPARSE (element); + GstRiffRead *riff = GST_RIFF_READ (wav); - case GST_WAVPARSE_OTHER: - GST_DEBUG ("riff tag: %4.4s %08x", (char *) &chunk.id, chunk.size); - - switch (chunk.id) { - case GST_RIFF_TAG_data: - wavparse->state = GST_WAVPARSE_DATA; - wavparse->dataleft = chunk.size; - wavparse->byteoffset = 0; - flush = 0; - break; + if (wav->state == GST_WAVPARSE_DATA) { + if (wav->dataleft > 0) { + guint32 got_bytes, desired; + GstBuffer *buf; - case GST_RIFF_TAG_fmt: - gst_wavparse_parse_fmt (wavparse, chunk.size); - flush = 0; - break; + desired = MIN (wav->dataleft, MAX_BUFFER_SIZE); - case GST_RIFF_TAG_cue: - //gst_wavparse_parse_cues (wavparse, chunk.size); - break; + buf = gst_riff_read_element_data (riff, desired, &got_bytes); - case GST_RIFF_TAG_LIST: - GST_DEBUG ("list type: %4.4s", (char *) &chunk.type); - switch (chunk.type) { - case GST_RIFF_LIST_INFO: - //gst_wavparse_parse_info (wavparse, chunk.size - 4); - //flush = 0; + gst_pad_push (wav->srcpad, GST_DATA (buf)); - break; + wav->byteoffset += got_bytes; + if (got_bytes < wav->dataleft) { + wav->dataleft -= got_bytes; + return; + } else { + wav->dataleft = 0; + wav->state = GST_WAVPARSE_OTHER; + } + } else { + wav->state = GST_WAVPARSE_OTHER; + } + } - case GST_RIFF_LIST_adtl: - //gst_wavparse_parse_adtl (wavparse, chunk.size - 4); - //flush = 0; - break; + switch (wav->state) { + case GST_WAVPARSE_START: + if (!gst_wavparse_stream_init (wav)) { + return; + } - default: - //flush = 0; - break; - } - break; + wav->state = GST_WAVPARSE_FMT; + /* fall-through */ - default: - GST_DEBUG (" ***** unknown chunkid %08x", chunk.id); - //flush = 0; - break; + case GST_WAVPARSE_FMT: + if (!gst_wavparse_fmt (wav)) { + return; } - break; - case GST_WAVPARSE_DATA: - /* Should have been handled up there ^^^^ */ - flush = 0; - break; + wav->state = GST_WAVPARSE_OTHER; + /* fall-through */ - default: - /* Unknown */ - g_warning ("Unknown state %d\n", wavparse->state); - //GST_DEBUG (" ***** unknown chunkid %08x", chunk.id); - break; - } + case GST_WAVPARSE_OTHER: + if (!gst_wavparse_other (wav)) { + return; + } - if (flush > 0) { - gboolean res; + break; - res = gst_bytestream_flush (bs, flush); - if (!res) { - guint32 remaining; - GstEvent *event; + case GST_WAVPARSE_DATA: - gst_bytestream_get_status (bs, &remaining, &event); - gst_event_unref (event); - } + default: + g_assert_not_reached (); } } @@ -1153,27 +1027,35 @@ gst_wavparse_srcpad_event (GstPad * pad, GstEvent * event) static GstElementStateReturn gst_wavparse_change_state (GstElement * element) { - GstWavParse *wavparse = GST_WAVPARSE (element); + GstWavParse *wav = GST_WAVPARSE (element); switch (GST_STATE_TRANSITION (element)) { case GST_STATE_NULL_TO_READY: break; + case GST_STATE_READY_TO_PAUSED: - wavparse->bs = gst_bytestream_new (wavparse->sinkpad); - wavparse->state = GST_WAVPARSE_START; + wav->state = GST_WAVPARSE_START; break; + case GST_STATE_PAUSED_TO_PLAYING: break; + case GST_STATE_PLAYING_TO_PAUSED: break; + case GST_STATE_PAUSED_TO_READY: - gst_wavparse_destroy_sourcepad (wavparse); - gst_bytestream_destroy (wavparse->bs); - wavparse->state = GST_WAVPARSE_UNKNOWN; - wavparse->bps = 0; - wavparse->seek_pending = FALSE; - wavparse->seek_offset = 0; + gst_wavparse_destroy_sourcepad (wav); + wav->state = GST_WAVPARSE_START; + + wav->width = 0; + wav->depth = 0; + wav->rate = 0; + wav->channels = 0; + + wav->seek_pending = FALSE; + wav->seek_offset = 0; break; + case GST_STATE_READY_TO_NULL: break; } @@ -1187,7 +1069,7 @@ gst_wavparse_change_state (GstElement * element) static gboolean plugin_init (GstPlugin * plugin) { - if (!gst_library_load ("gstbytestream")) { + if (!gst_library_load ("riff")) { return FALSE; } diff --git a/gst/wavparse/gstwavparse.h b/gst/wavparse/gstwavparse.h index 3893a29..024c25c 100644 --- a/gst/wavparse/gstwavparse.h +++ b/gst/wavparse/gstwavparse.h @@ -23,8 +23,8 @@ #include -#include -#include +#include "gst/riff/riff-ids.h" +#include "gst/riff/riff-read.h" #ifdef __cplusplus extern "C" { @@ -42,41 +42,39 @@ extern "C" { #define GST_IS_WAVPARSE_CLASS(obj) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WAVPARSE)) +typedef enum { + GST_WAVPARSE_START, + GST_WAVPARSE_FMT, + GST_WAVPARSE_OTHER, + GST_WAVPARSE_DATA, +} GstWavParseState; -#define GST_WAVPARSE_UNKNOWN 0 /* initialized state */ -#define GST_WAVPARSE_START 1 /* At the start */ -#define GST_WAVPARSE_DATA 2 /* in data region */ -#define GST_WAVPARSE_OTHER 3 /* in unknown region */ - typedef struct _GstWavParse GstWavParse; typedef struct _GstWavParseClass GstWavParseClass; struct _GstWavParse { - GstElement element; + GstRiffRead parent; - GstByteStream *bs; /* pads */ GstPad *sinkpad,*srcpad; /* WAVE decoding state */ - gint state; + GstWavParseState state; /* format of audio, see defines below */ gint format; /* useful audio data */ - gint bps; + guint16 depth; gint rate; - gint channels; - gint width; + guint16 channels; + guint16 width; - int dataleft; + guint64 dataleft; int byteoffset; gboolean seek_pending; guint64 seek_offset; - - GstBuffer *buf; }; struct _GstWavParseClass { @@ -85,16 +83,14 @@ struct _GstWavParseClass { GType gst_wavparse_get_type(void); -typedef struct _GstWavParseFormat GstWavParseFormat; - -struct _GstWavParseFormat { +typedef struct _gst_riff_fmt { gint16 wFormatTag; guint16 wChannels; guint32 dwSamplesPerSec; guint32 dwAvgBytesPerSec; guint16 wBlockAlign; guint16 wBitsPerSample; -}; +} gst_riff_fmt; /**** from public Microsoft RIFF docs ******/ -- 2.7.4