diff options
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | gst/wavparse/Makefile.am | 9 | ||||
-rw-r--r-- | gst/wavparse/gstwavparse.c | 599 | ||||
-rw-r--r-- | gst/wavparse/gstwavparse.h | 10 |
5 files changed, 411 insertions, 218 deletions
@@ -1,3 +1,12 @@ +2005-07-20 Edward Hervey <edward@fluendo.com> + + * configure.ac: + * gst/wavparse/gstwavparse.c: + * gst/wavparse/gstwavparse.h: + * gst/wavparse/Makefile.am: + Ported wavparse to 0.9 . Playing, seeking and state changes work. + Could need more loving on the headers though. + 2005-07-20 Ronald S. Bultje <rbultje@ronald.bitfreak.net> * configure.ac: diff --git a/configure.ac b/configure.ac index bac10af7..f01840ed 100644 --- a/configure.ac +++ b/configure.ac @@ -315,6 +315,7 @@ GST_PLUGINS_ALL="\ smpte \ udp \ videobox \ + wavparse \ " dnl see if we can build C++ plug-ins @@ -597,6 +598,7 @@ gst/smpte/Makefile gst/udp/Makefile gst/videobox/Makefile gst/videofilter/Makefile +gst/wavparse/Makefile gst-libs/Makefile gst-libs/gst/Makefile sys/Makefile diff --git a/gst/wavparse/Makefile.am b/gst/wavparse/Makefile.am index 0f7df636..b2887ee4 100644 --- a/gst/wavparse/Makefile.am +++ b/gst/wavparse/Makefile.am @@ -2,8 +2,11 @@ plugin_LTLIBRARIES = libgstwavparse.la libgstwavparse_la_SOURCES = gstwavparse.c -libgstwavparse_la_CFLAGS = $(GST_CFLAGS) -libgstwavparse_la_LIBADD = -libgstwavparse_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstwavparse_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \ + -I$(top_srcdir)/gst-libs +libgstwavparse_la_LIBADD = -lgstriff-0.9 +libgstwavparse_la_LDFLAGS = \ + $(GST_PLUGIN_LDFLAGS) \ + $(GST_PLUGINS_BASE_LIBS) noinst_HEADERS = gstwavparse.h diff --git a/gst/wavparse/gstwavparse.c b/gst/wavparse/gstwavparse.c index 4c343dcb..98d2809e 100644 --- a/gst/wavparse/gstwavparse.c +++ b/gst/wavparse/gstwavparse.c @@ -39,18 +39,18 @@ static void gst_wavparse_base_init (gpointer g_class); static void gst_wavparse_class_init (GstWavParseClass * klass); static void gst_wavparse_init (GstWavParse * wavparse); +static gboolean gst_wavparse_sink_activate (GstPad * sinkpad); +static gboolean gst_wavparse_sink_activate_pull (GstPad * sinkpad, + gboolean active); static GstElementStateReturn gst_wavparse_change_state (GstElement * element); -static const GstFormat *gst_wavparse_get_formats (GstPad * pad); +static gboolean gst_wavparse_pad_query (GstPad * pad, GstQuery * query); static const GstQueryType *gst_wavparse_get_query_types (GstPad * pad); -static gboolean gst_wavparse_pad_query (GstPad * pad, - GstQueryType type, GstFormat * format, gint64 * value); static gboolean gst_wavparse_pad_convert (GstPad * pad, GstFormat src_format, gint64 src_value, GstFormat * dest_format, gint64 * dest_value); -static void gst_wavparse_loop (GstElement * element); -static const GstEventMask *gst_wavparse_get_event_masks (GstPad * pad); +static void gst_wavparse_loop (GstPad * pad); static gboolean gst_wavparse_srcpad_event (GstPad * pad, GstEvent * event); static void gst_wavparse_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); @@ -130,7 +130,7 @@ gst_wavparse_get_type (void) }; wavparse_type = - g_type_register_static (GST_TYPE_RIFF_READ, "GstWavParse", + g_type_register_static (GST_TYPE_ELEMENT, "GstWavParse", &wavparse_info, 0); } return wavparse_type; @@ -165,7 +165,7 @@ gst_wavparse_class_init (GstWavParseClass * klass) gstelement_class = (GstElementClass *) klass; object_class = (GObjectClass *) klass; - parent_class = g_type_class_ref (GST_TYPE_RIFF_READ); + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); object_class->get_property = gst_wavparse_get_property; gstelement_class->change_state = gst_wavparse_change_state; @@ -174,40 +174,8 @@ gst_wavparse_class_init (GstWavParseClass * klass) } static void -gst_wavparse_init (GstWavParse * wavparse) +gst_wavparse_reset (GstWavParse * wavparse) { - /* sink */ - wavparse->sinkpad = - 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 = - 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_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, - gst_wavparse_get_query_types); - gst_pad_set_query_function (wavparse->srcpad, gst_wavparse_pad_query); - gst_pad_set_event_function (wavparse->srcpad, gst_wavparse_srcpad_event); - 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_START; /* These will all be set correctly in the fmt chunk */ @@ -215,9 +183,33 @@ gst_wavparse_init (GstWavParse * wavparse) wavparse->rate = 0; wavparse->width = 0; wavparse->channels = 0; - + wavparse->blockalign = 0; + wavparse->bps = 0; + wavparse->dataleft = 0; + wavparse->datasize = 0; + wavparse->datastart = 0; + + if (wavparse->seek_event) + gst_event_unref (wavparse->seek_event); + wavparse->seek_event = NULL; wavparse->seek_pending = FALSE; - wavparse->seek_offset = 0; + wavparse->seek_offset = (guint64) - 1; +} + +static void +gst_wavparse_init (GstWavParse * wavparse) +{ + /* sink */ + wavparse->sinkpad = + gst_pad_new_from_template (gst_static_pad_template_get + (&sink_template_factory), "sink"); + gst_element_add_pad (GST_ELEMENT (wavparse), wavparse->sinkpad); + wavparse->sinkpad = wavparse->sinkpad; + + gst_pad_set_activate_function (wavparse->sinkpad, gst_wavparse_sink_activate); + gst_pad_set_activatepull_function (wavparse->sinkpad, + gst_wavparse_sink_activate_pull); + gst_wavparse_reset (wavparse); } static void @@ -238,15 +230,11 @@ gst_wavparse_create_sourcepad (GstWavParse * wavparse) wavparse->srcpad = gst_pad_new_from_template (gst_static_pad_template_get (&src_template_factory), "src"); - gst_pad_use_explicit_caps (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_use_fixed_caps (wavparse->srcpad); gst_pad_set_query_type_function (wavparse->srcpad, gst_wavparse_get_query_types); gst_pad_set_query_function (wavparse->srcpad, gst_wavparse_pad_query); gst_pad_set_event_function (wavparse->srcpad, gst_wavparse_srcpad_event); - gst_pad_set_event_mask_function (wavparse->srcpad, - gst_wavparse_get_event_masks); } static void @@ -514,54 +502,84 @@ gst_wavparse_parse_cues (GstWavParse * wavparse, int len) #endif static gboolean -gst_wavparse_stream_init (GstWavParse * wav) +gst_wavparse_parse_file_header (GstElement * element, GstBuffer * buf) { - GstRiffRead *riff = GST_RIFF_READ (wav); guint32 doctype; - if (!gst_riff_read_header (riff, &doctype)) { - GST_WARNING_OBJECT (wav, "could not read header"); + if (!gst_riff_parse_file_header (element, buf, &doctype)) return FALSE; - } if (doctype != GST_RIFF_RIFF_WAVE) { - GST_ELEMENT_ERROR (wav, STREAM, WRONG_TYPE, (NULL), (NULL)); + GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL), + ("File is not an WAVE file: " GST_FOURCC_FORMAT, + GST_FOURCC_ARGS (doctype))); return FALSE; } return TRUE; } +static GstFlowReturn +gst_wavparse_stream_init (GstWavParse * wav) +{ + GstFlowReturn res; + GstBuffer *buf = NULL; + + if ((res = gst_pad_pull_range (wav->sinkpad, + wav->offset, 12, &buf)) != GST_FLOW_OK) + return res; + else if (!gst_wavparse_parse_file_header (GST_ELEMENT (wav), buf)) + return GST_FLOW_ERROR; + + wav->offset += 12; + + return GST_FLOW_OK; +} + +#if 0 /* Read 'fmt ' header */ static gboolean gst_wavparse_fmt (GstWavParse * wav) { - GstRiffRead *riff = GST_RIFF_READ (wav); gst_riff_strf_auds *header = NULL; GstCaps *caps; - if (!gst_riff_read_strf_auds (riff, &header)) { + if (!gst_riff_read_strf_auds (wav, &header)) { g_warning ("Not fmt"); return FALSE; } - /* Note: gst_riff_create_audio_caps might nedd to fix values in - * the header header depending on the format, so call it first */ - caps = gst_riff_create_audio_caps (header->format, NULL, header, NULL); - wav->format = header->format; wav->rate = header->rate; wav->channels = header->channels; + if (wav->channels == 0) { + GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL), + ("Stream claims to contain zero channels - invalid data")); + g_free (header); + return FALSE; + } wav->blockalign = header->blockalign; wav->width = (header->blockalign * 8) / header->channels; wav->depth = header->size; wav->bps = header->av_bps; + if (wav->bps <= 0) { + GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL), + ("Stream claims to bitrate of <= zero - invalid data")); + g_free (header); + return FALSE; + } + + /* Note: gst_riff_create_audio_caps might nedd to fix values in + * the header header depending on the format, so call it first */ + caps = gst_riff_create_audio_caps (header->format, NULL, header, NULL); g_free (header); if (caps) { gst_wavparse_create_sourcepad (wav); - gst_pad_set_explicit_caps (wav->srcpad, caps); + gst_pad_use_fixed_caps (wav->srcpad); + gst_pad_set_active (wav->srcpad, TRUE); + gst_pad_set_caps (wav->srcpad, caps); gst_caps_free (caps); gst_element_add_pad (GST_ELEMENT (wav), wav->srcpad); gst_element_no_more_pads (GST_ELEMENT (wav)); @@ -577,10 +595,9 @@ gst_wavparse_fmt (GstWavParse * wav) static gboolean gst_wavparse_other (GstWavParse * wav) { - GstRiffRead *riff = GST_RIFF_READ (wav); guint32 tag, length; - if (!gst_riff_peek_head (riff, &tag, &length, NULL)) { + if (!gst_riff_peek_head (wav, &tag, &length, NULL)) { GST_WARNING_OBJECT (wav, "could not peek head"); return FALSE; } @@ -589,21 +606,21 @@ gst_wavparse_other (GstWavParse * wav) switch (tag) { case GST_RIFF_TAG_LIST: - if (!(tag = gst_riff_peek_list (riff))) { + if (!(tag = gst_riff_peek_list (wav))) { GST_WARNING_OBJECT (wav, "could not peek list"); return FALSE; } switch (tag) { case GST_RIFF_LIST_INFO: - if (!gst_riff_read_list (riff, &tag) || !gst_riff_read_info (riff)) { + if (!gst_riff_read_list (wav, &tag) || !gst_riff_read_info (wav)) { GST_WARNING_OBJECT (wav, "could not read list"); return FALSE; } break; case GST_RIFF_LIST_adtl: - if (!gst_riff_read_skip (riff)) { + if (!gst_riff_read_skip (wav)) { GST_WARNING_OBJECT (wav, "could not read skip"); return FALSE; } @@ -612,7 +629,7 @@ gst_wavparse_other (GstWavParse * wav) default: GST_DEBUG_OBJECT (wav, "skipping tag (%08x) %4.4s", tag, (gchar *) & tag); - if (!gst_riff_read_skip (riff)) { + if (!gst_riff_read_skip (wav)) { GST_WARNING_OBJECT (wav, "could not read skip"); return FALSE; } @@ -622,14 +639,14 @@ gst_wavparse_other (GstWavParse * wav) break; case GST_RIFF_TAG_data: - if (!gst_bytestream_flush (riff->bs, 8)) { + if (!gst_bytestream_flush (wav->bs, 8)) { GST_WARNING_OBJECT (wav, "could not flush 8 bytes"); return FALSE; } GST_DEBUG_OBJECT (wav, "switching to data mode"); wav->state = GST_WAVPARSE_DATA; - wav->datastart = gst_bytestream_tell (riff->bs); + wav->datastart = gst_bytestream_tell (wav->bs); if (length == 0) { guint64 file_length; @@ -637,7 +654,7 @@ gst_wavparse_other (GstWavParse * wav) * of file */ GST_DEBUG_OBJECT (wav, "length is 0 trying to find length"); /* get length of file */ - file_length = gst_bytestream_length (riff->bs); + file_length = gst_bytestream_length (wav->bs); if (file_length == -1) { GST_DEBUG_OBJECT (wav, "could not get file length, assuming data to eof"); @@ -649,8 +666,8 @@ gst_wavparse_other (GstWavParse * wav) /* could not get length, assuming till eof */ length = G_MAXUINT32; } else { - GST_DEBUG_OBJECT (wav, "file length %lld, datalength", file_length, - length); + GST_DEBUG_OBJECT (wav, "file length %lld, datalength", + file_length, length); /* substract offset of datastart from length */ length = file_length - wav->datastart; GST_DEBUG_OBJECT (wav, "datalength %lld", length); @@ -660,7 +677,7 @@ gst_wavparse_other (GstWavParse * wav) break; case GST_RIFF_TAG_cue: - if (!gst_riff_read_skip (riff)) { + if (!gst_riff_read_skip (wav)) { GST_WARNING_OBJECT (wav, "could not read skip"); return FALSE; } @@ -668,137 +685,247 @@ gst_wavparse_other (GstWavParse * wav) default: GST_DEBUG_OBJECT (wav, "skipping tag (%08x) %4.4s", tag, (gchar *) & tag); - if (!gst_riff_read_skip (riff)) + if (!gst_riff_read_skip (wav)) return FALSE; break; } return TRUE; } +#endif static gboolean gst_wavparse_handle_seek (GstWavParse * wav) { - GstRiffRead *riff = GST_RIFF_READ (wav); - GstEvent *event = NULL; - guint32 remaining; - guint8 *data; + gst_pad_push_event (wav->srcpad, gst_event_new_flush (FALSE)); - if (!gst_bytestream_seek (riff->bs, wav->seek_offset + wav->datastart, - GST_SEEK_METHOD_SET)) - return FALSE; + GST_STREAM_LOCK (wav->sinkpad); - /* wait for discont */ - while (!event) { - if (gst_bytestream_peek_bytes (riff->bs, &data, 1)) { - GST_WARNING ("Unexpected data after seek - this means seek failed"); - return FALSE; - } + wav->offset = wav->seek_offset + wav->datastart; + wav->dataleft = wav->datasize - wav->seek_offset; - /* get the discont event and return */ - gst_bytestream_get_status (riff->bs, &remaining, &event); - if (!event) { - GST_WARNING ("No discontinuity event after seek - seek failed"); - return FALSE; - } else if (GST_EVENT_TYPE (event) != GST_EVENT_DISCONTINUOUS) { - GstEventType type = GST_EVENT_TYPE (event); + /* + FIXME : currently the seek/discont doesn't care about the stop value ! + */ + wav->seek_event = gst_event_new_discontinuous (1.0, + GST_FORMAT_TIME, + GST_SECOND * + wav->seek_offset / wav->bps, GST_SECOND * wav->datasize / wav->bps, NULL); - gst_pad_event_default (riff->sinkpad, event); - if (type == GST_EVENT_EOS) - return FALSE; + gst_pad_push_event (wav->srcpad, gst_event_new_flush (TRUE)); - event = NULL; - } + gst_pad_start_task (wav->sinkpad, (GstTaskFunction) gst_wavparse_loop, + wav->sinkpad); + + GST_STREAM_UNLOCK (wav->sinkpad); + + return TRUE; + +} + +static GstFlowReturn +gst_wavparse_stream_headers (GstWavParse * wav) +{ + GstFlowReturn res; + GstBuffer *buf, *extra; + gst_riff_strf_auds *header = NULL; + guint32 tag; + gboolean gotdata = FALSE; + GstCaps *caps; + + /* The header start with a 'fmt ' tag */ + if ((res = gst_riff_read_chunk (GST_ELEMENT (wav), wav->sinkpad, + &wav->offset, &tag, &buf)) != GST_FLOW_OK) + return res; + else if (tag != GST_RIFF_TAG_fmt) { + GST_ELEMENT_ERROR (wav, STREAM, DEMUX, (NULL), + ("Invalid WAV header (no fmt at start): " + GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag))); + return GST_FLOW_ERROR; + } + if (!(gst_riff_parse_strf_auds (GST_ELEMENT (wav), buf, &header, &extra))) { + GST_ELEMENT_ERROR (wav, STREAM, DEMUX, (NULL), + ("Couldn't parse audio header")); + gst_buffer_unref (buf); + return GST_FLOW_ERROR; } - wav->dataleft = wav->datasize - wav->seek_offset; + caps = + gst_riff_create_audio_caps (header->format, NULL, header, NULL, + NULL, NULL); - gst_event_unref (event); - event = gst_event_new_discontinuous (FALSE, - GST_FORMAT_BYTES, wav->seek_offset, - GST_FORMAT_TIME, GST_SECOND * wav->seek_offset / wav->bps, - GST_FORMAT_UNDEFINED); - gst_pad_event_default (wav->sinkpad, event); + wav->format = header->format; + wav->rate = header->rate; + wav->channels = header->channels; + wav->blockalign = header->blockalign; + wav->width = (header->blockalign * 8) / header->channels; + wav->depth = header->size; + wav->bps = header->av_bps; - return TRUE; + g_free (header); + + if (caps) { + gst_wavparse_create_sourcepad (wav); +/* gst_pad_use_fixed_caps (wav->srcpad); */ + gst_pad_set_active (wav->srcpad, TRUE); + gst_pad_set_caps (wav->srcpad, caps); +/* gst_caps_free (caps); */ + gst_element_add_pad (GST_ELEMENT (wav), wav->srcpad); + gst_element_no_more_pads (GST_ELEMENT (wav)); + GST_DEBUG ("frequency %d, channels %d", wav->rate, wav->channels); + } else { + GST_ELEMENT_ERROR (wav, STREAM, TYPE_NOT_FOUND, (NULL), (NULL)); + return GST_FLOW_ERROR; + } + + + /* loop headers until we get data */ + while (!gotdata) { + guint size; + guint32 tag; + + if ((res = + gst_pad_pull_range (wav->sinkpad, wav->offset, 8, + &buf)) != GST_FLOW_OK) { + GST_ELEMENT_ERROR (wav, STREAM, DEMUX, (NULL), + ("Couldn't read in header")); + return GST_FLOW_ERROR; + } + + /* + wav is a st00pid format, we don't know for sure where data starts. + So we have to go bit by bit until we find the 'data' header + */ + tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf)); + size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 4); + switch (tag) { + /* TODO : Implement the various cases */ + case GST_RIFF_TAG_data: + GST_DEBUG ("Got 'data' TAG, size : %d", size); + gotdata = TRUE; + wav->offset += 8; + wav->datastart = wav->offset; + wav->datasize = size; + wav->dataleft = wav->datasize; + break; + default: + GST_DEBUG ("Ignoring tag" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)); + wav->offset += 8 + ((size + 1) & ~1); + } + gst_buffer_unref (buf); + } + + GST_DEBUG ("Finished parsing headers"); + /* Initial discont */ + wav->seek_event = gst_event_new_discontinuous (1.0, + GST_FORMAT_TIME, + (gint64) 0, (gint64) GST_SECOND * wav->datasize / wav->bps, NULL); + + return GST_FLOW_OK; } #define MAX_BUFFER_SIZE 4096 -static void -gst_wavparse_loop (GstElement * element) +static GstFlowReturn +gst_wavparse_stream_data (GstWavParse * wav) { - GstWavParse *wav = GST_WAVPARSE (element); - GstRiffRead *riff = GST_RIFF_READ (wav); - - if (wav->state == GST_WAVPARSE_DATA) { - /* seek handling */ - if (wav->seek_pending) { - gst_wavparse_handle_seek (wav); - wav->seek_pending = FALSE; - } + GstBuffer *buf = NULL; + GstFlowReturn res = GST_FLOW_OK; + guint64 desired, obtained; + + GST_DEBUG ("stream data !!!"); + /* Get the next n bytes and output them */ + if (wav->dataleft == 0) { + if ((res = + gst_pad_push_event (wav->srcpad, + gst_event_new (GST_EVENT_EOS))) != GST_FLOW_OK) + return res; + return GST_FLOW_WRONG_STATE; + } - if (wav->dataleft > 0) { - guint32 got_bytes, desired; - GstBuffer *buf = NULL; + GST_DEBUG ("offset : %lld , dataleft : %lld", wav->offset, wav->dataleft); - desired = MIN (wav->dataleft, MAX_BUFFER_SIZE); - if (!(buf = gst_riff_read_element_data (riff, desired, &got_bytes))) { - GST_WARNING_OBJECT (wav, "trying to read %d bytes failed", desired); - return; - } - GST_DEBUG_OBJECT (wav, "read %d bytes, got %d bytes", desired, got_bytes); + desired = MIN (wav->dataleft, MAX_BUFFER_SIZE); + GST_DEBUG ("Fetching %lld bytes of data from the sinkpad.", desired); + if ((res = gst_pad_pull_range (wav->sinkpad, wav->offset, + desired, &buf)) != GST_FLOW_OK) { + GST_DEBUG ("Error getting %ldd bytes from the sinkpad!", desired); + return res; + } - GST_BUFFER_TIMESTAMP (buf) = GST_SECOND * - (wav->datasize - wav->dataleft) / wav->bps; - GST_BUFFER_DURATION (buf) = GST_SECOND * got_bytes / wav->bps; + obtained = GST_BUFFER_SIZE (buf); + GST_BUFFER_TIMESTAMP (buf) = + GST_SECOND * (wav->datasize - wav->dataleft) / wav->bps; + GST_BUFFER_DURATION (buf) = GST_SECOND * obtained / wav->bps; + gst_buffer_set_caps (buf, GST_PAD_CAPS (wav->srcpad)); - gst_pad_push (wav->srcpad, GST_DATA (buf)); + GST_DEBUG ("Got buffer. timestamp:%lld , duration:%lld, size:%lld", + GST_BUFFER_TIMESTAMP (buf), + GST_BUFFER_DURATION (buf), GST_BUFFER_SIZE (buf)); - 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; - } + if ((res = gst_pad_push (wav->srcpad, buf)) != GST_FLOW_OK) { + GST_DEBUG ("Error pushing on srcpad"); + return res; + } + if (obtained < wav->dataleft) { + wav->dataleft -= obtained; + wav->offset += obtained; + } else { + wav->dataleft = 0; } + return res; +} + +static void +gst_wavparse_loop (GstPad * pad) +{ + GstFlowReturn ret; + GstWavParse *wav = GST_WAVPARSE (GST_PAD_PARENT (pad)); + switch (wav->state) { case GST_WAVPARSE_START: - if (!gst_wavparse_stream_init (wav)) { - return; - } + if ((ret = gst_wavparse_stream_init (wav)) != GST_FLOW_OK) + goto pause; - wav->state = GST_WAVPARSE_FMT; + wav->state = GST_WAVPARSE_HEADER; /* fall-through */ - case GST_WAVPARSE_FMT: - if (!gst_wavparse_fmt (wav)) { - return; + case GST_WAVPARSE_HEADER: + if ((ret = gst_wavparse_stream_headers (wav)) != GST_FLOW_OK) { + goto pause; } - wav->state = GST_WAVPARSE_OTHER; + wav->state = GST_WAVPARSE_DATA; /* fall-through */ - - case GST_WAVPARSE_OTHER: - if (!gst_wavparse_other (wav)) { - return; + case GST_WAVPARSE_DATA: + if (wav->seek_event) { + gst_pad_push_event (wav->srcpad, wav->seek_event); + wav->seek_event = NULL; } - + if ((ret = gst_wavparse_stream_data (wav)) != GST_FLOW_OK) + goto pause; break; - - case GST_WAVPARSE_DATA: - default: g_assert_not_reached (); + + } + + return; + +pause: + GST_LOG_OBJECT (wav, "pausing task %d", ret); + gst_pad_pause_task (wav->sinkpad); + if (GST_FLOW_IS_FATAL (ret)) { + /* for fatal errors we post an error message */ + GST_ELEMENT_ERROR (wav, STREAM, STOPPED, + ("streaming stopped, reason %d", ret), + ("streaming stopped, reason %d", ret)); + gst_pad_push_event (wav->srcpad, gst_event_new (GST_EVENT_EOS)); } } +#if 0 /* convert and query stuff */ static const GstFormat * gst_wavparse_get_formats (GstPad * pad) @@ -812,6 +939,7 @@ gst_wavparse_get_formats (GstPad * pad) return formats; } +#endif static gboolean gst_wavparse_pad_convert (GstPad * pad, @@ -825,7 +953,8 @@ gst_wavparse_pad_convert (GstPad * pad, bytes_per_sample = wavparse->channels * wavparse->width / 8; if (bytes_per_sample == 0) { - GST_DEBUG ("bytes_per_sample 0, probably an mp3 - channels %d, width %d", + GST_DEBUG + ("bytes_per_sample 0, probably an mp3 - channels %d, width %d", wavparse->channels, wavparse->width); return FALSE; } @@ -890,7 +1019,6 @@ static const GstQueryType * gst_wavparse_get_query_types (GstPad * pad) { static const GstQueryType types[] = { - GST_QUERY_TOTAL, GST_QUERY_POSITION, 0 }; @@ -900,75 +1028,114 @@ gst_wavparse_get_query_types (GstPad * pad) /* handle queries for location and length in requested format */ static gboolean -gst_wavparse_pad_query (GstPad * pad, GstQueryType type, - GstFormat * format, gint64 * value) +gst_wavparse_pad_query (GstPad * pad, GstQuery * query) { - gint64 bytevalue; - GstWavParse *wav = GST_WAVPARSE (gst_pad_get_parent (pad)); + gboolean res = TRUE; + GstWavParse *wav = GST_WAVPARSE (GST_PAD_PARENT (pad)); /* only if we know */ if (wav->state != GST_WAVPARSE_DATA) return FALSE; - switch (type) { + switch (GST_QUERY_TYPE (query)) { case GST_QUERY_POSITION: - bytevalue = wav->datasize - wav->dataleft; + { + gint64 curb, endb; + gint64 cur, end; + GstFormat format; + gboolean res = TRUE; + + curb = wav->datasize - wav->dataleft; + endb = wav->datasize; + gst_query_parse_position (query, &format, NULL, NULL); + + switch (format) { + case GST_FORMAT_TIME: + res &= + gst_wavparse_pad_convert (pad, GST_FORMAT_BYTES, curb, + &format, &cur); + res &= + gst_wavparse_pad_convert (pad, GST_FORMAT_BYTES, endb, + &format, &end); + break; + default: + format = GST_FORMAT_BYTES; + cur = curb; + end = endb; + break; + } + if (res) + gst_query_set_position (query, format, cur, end); break; - case GST_QUERY_TOTAL: - bytevalue = wav->datasize; + } + case GST_QUERY_CONVERT: + { + gint64 srcvalue, dstvalue; + GstFormat srcformat, dstformat; + + gst_query_parse_convert (query, &srcformat, &srcvalue, + &dstformat, &dstvalue); + res &= + gst_wavparse_pad_convert (pad, srcformat, srcvalue, + &dstformat, &dstvalue); + if (res) + gst_query_set_convert (query, srcformat, srcvalue, dstformat, dstvalue); break; + } default: - return FALSE; - } - - if (*format == GST_FORMAT_BYTES) { - *value = bytevalue; - return TRUE; + res = FALSE; + break; } - - return gst_pad_convert (wav->sinkpad, GST_FORMAT_BYTES, - bytevalue, format, value); -} - -static const GstEventMask * -gst_wavparse_get_event_masks (GstPad * pad) -{ - static const GstEventMask gst_wavparse_src_event_masks[] = { - {GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH}, - {0,} - }; - - return gst_wavparse_src_event_masks; + return res; } static gboolean gst_wavparse_srcpad_event (GstPad * pad, GstEvent * event) { GstWavParse *wavparse = GST_WAVPARSE (GST_PAD_PARENT (pad)); - gboolean res = FALSE; + gboolean res = TRUE; GST_DEBUG ("event %d", GST_EVENT_TYPE (event)); + /* TODO : we need to call handle_seek */ + switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: { - gint64 byteoffset; + gint64 bseek_start, bseek_stop; GstFormat format; + GstFormat dformat = GST_FORMAT_BYTES; + + format = GST_EVENT_SEEK_FORMAT (event); - /* bring format to samples for the peer element, */ - format = GST_FORMAT_BYTES; - res = gst_pad_convert (pad, - GST_EVENT_SEEK_FORMAT (event), - GST_EVENT_SEEK_OFFSET (event), &format, &byteoffset); + GST_DEBUG ("seek format %d", format); - if (res) { - /* ok, seek worked, update our state */ - wavparse->seek_offset = byteoffset; - wavparse->seek_pending = TRUE; + /* find the corresponding bytestream position */ + if (format == GST_FORMAT_BYTES) { + bseek_start = GST_EVENT_SEEK_OFFSET (event); + bseek_stop = GST_EVENT_SEEK_ENDOFFSET (event); + } else { + res &= + gst_wavparse_pad_convert (pad, format, + GST_EVENT_SEEK_OFFSET (event), &dformat, &bseek_start); + res &= + gst_wavparse_pad_convert (pad, format, + GST_EVENT_SEEK_ENDOFFSET (event), &dformat, &bseek_stop); + if (!res) + return res; + } + + if (bseek_start > wavparse->datasize) { + GST_WARNING ("seeking after end of data!"); + return FALSE; } + + wavparse->seek_offset = bseek_start; + gst_wavparse_handle_seek (wavparse); break; } default: + res = FALSE; break; } @@ -977,6 +1144,28 @@ gst_wavparse_srcpad_event (GstPad * pad, GstEvent * event) return res; } +static gboolean +gst_wavparse_sink_activate (GstPad * sinkpad) +{ + if (gst_pad_check_pull_range (sinkpad)) + return gst_pad_activate_pull (sinkpad, TRUE); + + return FALSE; +}; + +static gboolean +gst_wavparse_sink_activate_pull (GstPad * sinkpad, gboolean active) +{ + if (active) { + /* if we have a scheduler we can start the task */ + gst_pad_start_task (sinkpad, (GstTaskFunction) gst_wavparse_loop, sinkpad); + } else { + gst_pad_stop_task (sinkpad); + } + + return TRUE; +}; + static GstElementStateReturn gst_wavparse_change_state (GstElement * element) { @@ -998,15 +1187,7 @@ gst_wavparse_change_state (GstElement * element) case GST_STATE_PAUSED_TO_READY: 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; + gst_wavparse_reset (wav); break; case GST_STATE_READY_TO_NULL: @@ -1022,9 +1203,7 @@ gst_wavparse_change_state (GstElement * element) static gboolean plugin_init (GstPlugin * plugin) { - if (!gst_library_load ("riff")) { - return FALSE; - } + gst_riff_init (); return gst_element_register (plugin, "wavparse", GST_RANK_PRIMARY, GST_TYPE_WAVPARSE); diff --git a/gst/wavparse/gstwavparse.h b/gst/wavparse/gstwavparse.h index 1e79b16a..fbe9af8e 100644 --- a/gst/wavparse/gstwavparse.h +++ b/gst/wavparse/gstwavparse.h @@ -44,8 +44,7 @@ extern "C" { typedef enum { GST_WAVPARSE_START, - GST_WAVPARSE_FMT, - GST_WAVPARSE_OTHER, + GST_WAVPARSE_HEADER, GST_WAVPARSE_DATA, } GstWavParseState; @@ -53,13 +52,14 @@ typedef struct _GstWavParse GstWavParse; typedef struct _GstWavParseClass GstWavParseClass; struct _GstWavParse { - GstRiffRead parent; + GstElement parent; /* pads */ GstPad *sinkpad,*srcpad; /* WAVE decoding state */ GstWavParseState state; + guint64 offset; /* format of audio, see defines below */ gint format; @@ -73,14 +73,14 @@ struct _GstWavParse { guint32 bps; guint64 dataleft, datasize, datastart; - int byteoffset; gboolean seek_pending; + GstEvent *seek_event; guint64 seek_offset; }; struct _GstWavParseClass { - GstRiffReadClass parent_class; + GstElementClass parent_class; }; GType gst_wavparse_get_type(void); |