From ab71414650b5bfe8af2a0274c012f0ab872032b9 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sat, 1 Mar 2003 18:34:38 +0000 Subject: [PATCH] Implement seeking on wav Original commit message from CVS: Implement seeking on wav --- gst/wavparse/gstwavparse.c | 203 +++++++++++++++++++++++++------------ 1 file changed, 139 insertions(+), 64 deletions(-) diff --git a/gst/wavparse/gstwavparse.c b/gst/wavparse/gstwavparse.c index f4549df17a..9582e65fa7 100644 --- a/gst/wavparse/gstwavparse.c +++ b/gst/wavparse/gstwavparse.c @@ -22,24 +22,28 @@ #include -static void gst_wavparse_class_init (GstWavParseClass *klass); -static void gst_wavparse_init (GstWavParse *wavparse); +static void gst_wavparse_class_init (GstWavParseClass *klass); +static void gst_wavparse_init (GstWavParse *wavparse); -static GstCaps* wav_type_find (GstBuffer *buf, gpointer private); +static GstCaps* wav_type_find (GstBuffer *buf, gpointer private); static const GstFormat* gst_wavparse_get_formats (GstPad *pad); 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_chain (GstPad *pad, GstBuffer *buf); +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_chain (GstPad *pad, GstBuffer *buf); + +static const GstEventMask* + gst_wavparse_get_event_masks (GstPad *pad); +static gboolean gst_wavparse_srcpad_event (GstPad *pad, GstEvent *event); /* elementfactory information */ static GstElementDetails gst_wavparse_details = { @@ -172,6 +176,8 @@ gst_wavparse_init (GstWavParse *wavparse) 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); gst_pad_set_chain_function (wavparse->sinkpad, gst_wavparse_chain); @@ -183,6 +189,8 @@ gst_wavparse_init (GstWavParse *wavparse) wavparse->riff_nextlikely = 0; wavparse->size = 0; wavparse->bps = 0; + wavparse->offset = 0; + wavparse->need_discont = FALSE; } static GstCaps* @@ -196,37 +204,11 @@ wav_type_find (GstBuffer *buf, gpointer private) return gst_caps_new ("wav_type_find", "audio/x-wav", NULL); } - -/* set timestamp on outgoing buffer - * returns TRUE if a timestamp was set - */ -static gboolean -gst_wavparse_set_timestamp (GstWavParse *wavparse, GstBuffer *buf) -{ - gboolean retval = FALSE; - - /* only do timestamps on linear audio */ - switch (wavparse->format) - { - case GST_RIFF_WAVE_FORMAT_PCM: - GST_BUFFER_TIMESTAMP (buf) = wavparse->offset * GST_SECOND - / wavparse->rate; - wavparse->offset += GST_BUFFER_SIZE (buf) * 8 - / (wavparse->width * wavparse->channels); - retval = TRUE; - break; - default: - break; - } - return retval; -} - static void gst_wavparse_chain (GstPad *pad, GstBuffer *buf) { GstWavParse *wavparse; gboolean buffer_riffed = FALSE; /* so we don't parse twice */ - gchar *data; gulong size; g_return_if_fail (pad != NULL); @@ -237,29 +219,55 @@ gst_wavparse_chain (GstPad *pad, GstBuffer *buf) wavparse = GST_WAVPARSE (gst_pad_get_parent (pad)); GST_DEBUG (0, "gst_wavparse_chain: got buffer in '%s'", gst_object_get_name (GST_OBJECT (wavparse))); - data = (guchar *) GST_BUFFER_DATA (buf); + size = GST_BUFFER_SIZE (buf); /* walk through the states in priority order */ /* we're in the data region */ if (wavparse->state == GST_WAVPARSE_DATA) { + GstFormat format; + guint64 maxsize; + + /* we can't go beyond the max length */ + maxsize = wavparse->riff_nextlikely - GST_BUFFER_OFFSET (buf); + /* if we're expected to see a new chunk in this buffer */ - if ((wavparse->riff_nextlikely - GST_BUFFER_OFFSET (buf)) - < GST_BUFFER_SIZE (buf)) { - GST_BUFFER_SIZE (buf) = wavparse->riff_nextlikely - - GST_BUFFER_OFFSET (buf); + if (maxsize < size) { + GstBuffer *newbuf; + + newbuf = gst_buffer_create_sub (buf, 0, maxsize); + gst_buffer_unref (buf); + buf = newbuf; + + size = maxsize; wavparse->state = GST_WAVPARSE_OTHER; /* I suppose we could signal an EOF at this point, but that may be premature. We've stopped data flow, that's the main thing. */ } - gst_wavparse_set_timestamp (wavparse, buf); + if (GST_PAD_IS_USABLE (wavparse->srcpad)) { + format = GST_FORMAT_TIME; + gst_pad_convert (wavparse->srcpad, + GST_FORMAT_BYTES, + wavparse->offset, + &format, + &GST_BUFFER_TIMESTAMP (buf)); - if (GST_PAD_IS_USABLE (wavparse->srcpad)) + if (wavparse->need_discont) { + gst_pad_push (wavparse->srcpad, + GST_BUFFER (gst_event_new_discontinuous (FALSE, + GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buf), + NULL))); + wavparse->need_discont = FALSE; + } gst_pad_push (wavparse->srcpad, buf); + } else gst_buffer_unref (buf); + + wavparse->offset += size; + return; } @@ -396,6 +404,8 @@ gst_wavparse_chain (GstPad *pad, GstBuffer *buf) GST_DEBUG (0, "data begins at %ld", datachunk->offset); + wavparse->datastart = datachunk->offset; + /* at this point we can ACK that we have data */ wavparse->state = GST_WAVPARSE_DATA; @@ -403,22 +413,18 @@ gst_wavparse_chain (GstPad *pad, GstBuffer *buf) subsize = size - datachunk->offset; GST_DEBUG (0, "sending last %ld bytes along as audio", subsize); - newbuf = gst_buffer_new (); - GST_BUFFER_DATA (newbuf) = g_malloc (subsize); - GST_BUFFER_SIZE (newbuf) = subsize; - - gst_wavparse_set_timestamp (wavparse, newbuf); - - memcpy (GST_BUFFER_DATA (newbuf), - GST_BUFFER_DATA (buf) + datachunk->offset, subsize); - + newbuf = gst_buffer_create_sub (buf, datachunk->offset, subsize); gst_buffer_unref (buf); + GST_BUFFER_TIMESTAMP (newbuf) = 0; + if (GST_PAD_IS_USABLE (wavparse->srcpad)) gst_pad_push (wavparse->srcpad, newbuf); else gst_buffer_unref (newbuf); + wavparse->offset = subsize; + /* now we're ready to go, the next buffer should start data */ wavparse->state = GST_WAVPARSE_DATA; @@ -456,22 +462,23 @@ gst_wavparse_pad_convert (GstPad *pad, GstWavParse *wavparse; wavparse = GST_WAVPARSE (gst_pad_get_parent (pad)); + /* FIXME default should be samples in this case IMO */ if (*dest_format == GST_FORMAT_DEFAULT) *dest_format = GST_FORMAT_TIME; bytes_per_sample = wavparse->channels * wavparse->width / 8; if (bytes_per_sample == 0) { - g_warning ("bytes_per_sample is 0, internal error\n"); - g_warning ("channels %d, width %d\n", - wavparse->channels, wavparse->width); - return FALSE; + g_warning ("bytes_per_sample is 0, internal error\n"); + g_warning ("channels %d, width %d\n", + wavparse->channels, wavparse->width); + return FALSE; } byterate = (glong) (bytes_per_sample * wavparse->rate); if (byterate == 0) { - g_warning ("byterate is 0, internal error\n"); - return FALSE; + g_warning ("byterate is 0, internal error\n"); + return FALSE; } - g_print ("DEBUG: bytes per sample: %d\n", bytes_per_sample); + GST_DEBUG (0, "bytes per sample: %d\n", bytes_per_sample); switch (src_format) { case GST_FORMAT_BYTES: @@ -494,9 +501,11 @@ gst_wavparse_pad_convert (GstPad *pad, if (*dest_format == GST_FORMAT_BYTES) *dest_value = src_value * byterate / GST_SECOND; else if (*dest_format == GST_FORMAT_UNITS) - *dest_value = src_value * wavparse->rate /GST_SECOND; + *dest_value = src_value * wavparse->rate / GST_SECOND; else return FALSE; + + *dest_value = *dest_value & ~(bytes_per_sample - 1); break; default: g_warning ("unhandled format for wavparse\n"); @@ -539,10 +548,76 @@ gst_wavparse_pad_query (GstPad *pad, GstQueryType type, g_warning ("Could not query sink pad's peer\n"); return FALSE; } - g_print ("DEBUG: pad_query done, value %" G_GINT64_FORMAT "\n", *value); + GST_DEBUG (0, "pad_query done, value %" G_GINT64_FORMAT "\n", *value); return TRUE; } +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; +} + +static gboolean +gst_wavparse_srcpad_event (GstPad *pad, GstEvent *event) +{ + GstWavParse *wavparse = GST_WAVPARSE (GST_PAD_PARENT (pad)); + gboolean res = FALSE; + + GST_DEBUG(0, "event %d", GST_EVENT_TYPE (event)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_SEEK: + { + gint64 byteoffset; + GstFormat format; + + /* we can only seek when in the DATA state */ + if (wavparse->state != GST_WAVPARSE_DATA) { + return FALSE; + } + + format = GST_FORMAT_BYTES; + + /* bring format to bytes for the peer element, + * FIXME be smarter here */ + res = gst_pad_convert (pad, + GST_EVENT_SEEK_FORMAT (event), + GST_EVENT_SEEK_OFFSET (event), + &format, + &byteoffset); + + if (res) { + GstEvent *seek; + + /* seek to byteoffset + header length */ + seek = gst_event_new_seek ( + GST_FORMAT_BYTES | + (GST_EVENT_SEEK_TYPE (event) & ~GST_SEEK_FORMAT_MASK), + byteoffset + wavparse->datastart); + + res = gst_pad_send_event (GST_PAD_PEER (wavparse->sinkpad), seek); + + if (res) { + /* ok, seek worked, update our state */ + wavparse->offset = byteoffset; + wavparse->need_discont = TRUE; + } + } + break; + } + default: + break; + } + + gst_event_unref (event); + return res; +} static gboolean plugin_init (GModule *module, GstPlugin *plugin)