diff options
-rw-r--r-- | ChangeLog | 12 | ||||
-rw-r--r-- | PORTED_09 | 1 | ||||
-rw-r--r-- | configure.ac | 10 | ||||
-rw-r--r-- | ext/Makefile.am | 8 | ||||
-rw-r--r-- | ext/wavpack/Makefile.am | 8 | ||||
-rw-r--r-- | ext/wavpack/gstwavpackdec.c | 136 | ||||
-rw-r--r-- | ext/wavpack/gstwavpackdec.h | 7 | ||||
-rw-r--r-- | ext/wavpack/gstwavpackparse.c | 468 | ||||
-rw-r--r-- | ext/wavpack/gstwavpackparse.h | 7 |
9 files changed, 421 insertions, 236 deletions
@@ -1,3 +1,15 @@ +2005-11-25 Edgard Lima <edgard.lima@indt.org.br> + + * configure.ac: + * PORTED_09: + * ext/Makefile.am: + * ext/wavpack/Makefile.am: + * ext/wavpack/gstwavpackdec.c: + * ext/wavpack/gstwavpackdec.h: + * ext/wavpack/gstwavpackparse.c: + * ext/wavpack/gstwavpackparse.h: + Wavpack ported to 0.9. No support for correction file yet. + 2005-11-25 Thomas Vander Stichele <thomas at apestaart dot org> * ext/wavpack/Makefile.am: @@ -1,6 +1,7 @@ When porting a plugin start with 0.8 CVS head, not the old code in this module. There are many bugfixes which have gone into 0.8 which you want to keep. List of ported plugins (update when you commit a ported plugin): +wavpack (alima) musepack (alima) ivorbis (alima) gsmdec (alima) diff --git a/configure.ac b/configure.ac index dc922ece..ce1fcea5 100644 --- a/configure.ac +++ b/configure.ac @@ -418,6 +418,15 @@ GST_CHECK_FEATURE(SDL, [SDL plug-in], sdlvideosink, [ AM_PATH_SDL(, HAVE_SDL=yes, HAVE_SDL=no) ]) +dnl *** wavpack *** +dnl We ship our own version of the library +translit(dnm, m, l) AM_CONDITIONAL(USE_WAVPACK, true) +GST_CHECK_FEATURE(WAVPACK, [wavpack plug-in], wavpack, [ + PKG_CHECK_MODULES(WAVPACK, wavpack >= 4.2, HAVE_WAVPACK=yes, HAVE_WAVPACK=no) + AC_SUBST(WAVPACK_CFLAGS) + AC_SUBST(WAVPACK_LIBS) +]) + dnl *** ivorbis *** dnl AM_PATH_IVORBIS only takes two options translit(dnm, m, l) AM_CONDITIONAL(USE_IVORBIS, true) @@ -518,6 +527,7 @@ ext/Makefile ext/directfb/Makefile ext/faac/Makefile ext/faad/Makefile +ext/wavpack/Makefile ext/ivorbis/Makefile ext/gsm/Makefile ext/musepack/Makefile diff --git a/ext/Makefile.am b/ext/Makefile.am index 651664c8..f6fe9c87 100644 --- a/ext/Makefile.am +++ b/ext/Makefile.am @@ -76,6 +76,12 @@ endif HERMES_DIR= # endif +if USE_WAVPACK +WAVPACK_DIR=wavpack +else +WAVPACK_DIR= +endif + if USE_IVORBIS IVORBIS_DIR=ivorbis else @@ -231,4 +237,6 @@ DIST_SUBDIRS= \ musepack \ sdl \ directfb \ + musepack \ + wavpack \ ivorbis diff --git a/ext/wavpack/Makefile.am b/ext/wavpack/Makefile.am index b2ca835e..6660a726 100644 --- a/ext/wavpack/Makefile.am +++ b/ext/wavpack/Makefile.am @@ -1,10 +1,10 @@ plugin_LTLIBRARIES = libgstwavpack.la -libgstwavpack_la_SOURCES = gstwavpack.c \ - gstwavpackcommon.c \ - gstwavpackparse.c \ - gstwavpackdec.c +libgstwavpack_la_SOURCES = gstwavpack.c \ + gstwavpackcommon.c \ + gstwavpackparse.c \ + gstwavpackdec.c libgstwavpack_la_CFLAGS = $(GST_CFLAGS) $(WAVPACK_CFLAGS) libgstwavpack_la_LIBADD = $(WAVPACK_LIBS) diff --git a/ext/wavpack/gstwavpackdec.c b/ext/wavpack/gstwavpackdec.c index d9fa074c..de7e87fd 100644 --- a/ext/wavpack/gstwavpackdec.c +++ b/ext/wavpack/gstwavpackdec.c @@ -76,20 +76,20 @@ static void gst_wavpack_dec_class_init (GstWavpackDecClass * klass); static void gst_wavpack_dec_base_init (GstWavpackDecClass * klass); static void gst_wavpack_dec_init (GstWavpackDec * wavpackdec); -static void gst_wavpack_dec_loop (GstElement * element); +static GstFlowReturn gst_wavpack_dec_chain (GstPad * pad, GstBuffer * buffer); static GstElementClass *parent = NULL; static GstPadLinkReturn -gst_wavpack_dec_link (GstPad * pad, const GstCaps * caps) +gst_wavpack_dec_link (GstPad * pad, GstPad * peer) { GstWavpackDec *wavpackdec = GST_WAVPACK_DEC (gst_pad_get_parent (pad)); - GstStructure *structure = gst_caps_get_structure (caps, 0); + GstStructure *structure = gst_caps_get_structure (GST_PAD_CAPS (peer), 0); GstCaps *srccaps; gint bits; - if (!gst_caps_is_fixed (caps)) - return GST_PAD_LINK_DELAYED; + if (!gst_caps_is_fixed (GST_PAD_CAPS (peer))) + return GST_PAD_LINK_REFUSED; gst_structure_get_int (structure, "rate", (gint32 *) & wavpackdec->samplerate); @@ -114,24 +114,22 @@ gst_wavpack_dec_link (GstPad * pad, const GstCaps * caps) "endianness", G_TYPE_INT, LITTLE_ENDIAN, "buffer-frames", G_TYPE_INT, 0, NULL); } + gst_pad_set_caps (wavpackdec->srcpad, srccaps); + gst_pad_use_fixed_caps (wavpackdec->srcpad); - gst_pad_set_explicit_caps (wavpackdec->srcpad, srccaps); - - // blocks are usually 0.5 seconds long, assume that's always the case for now - wavpackdec->decodebuf = - (int32_t *) g_malloc ((wavpackdec->samplerate / 2) * - wavpackdec->channels * sizeof (int32_t)); return GST_PAD_LINK_OK; } +#if 0 static GstPadLinkReturn -gst_wavpack_dec_wvclink (GstPad * pad, const GstCaps * caps) +gst_wavpack_dec_wvclink (GstPad * pad, GstPad * peer) { - if (!gst_caps_is_fixed (caps)) - return GST_PAD_LINK_DELAYED; + if (!gst_caps_is_fixed (GST_PAD_CAPS (peer))) + return GST_PAD_LINK_REFUSED; return GST_PAD_LINK_OK; } +#endif GType gst_wavpack_dec_get_type (void) @@ -201,10 +199,9 @@ gst_wavpack_dec_class_init (GstWavpackDecClass * klass) } static gboolean -gst_wavpack_dec_src_query (GstPad * pad, GstQueryType type, - GstFormat * format, gint64 * value) +gst_wavpack_dec_src_query (GstPad * pad, GstQuery * query) { - return gst_pad_query_default (pad, type, format, value); + return gst_pad_query_default (pad, query); } static void @@ -215,27 +212,31 @@ gst_wavpack_dec_init (GstWavpackDec * wavpackdec) wavpackdec->sinkpad = gst_pad_new_from_template (gst_element_class_get_pad_template (klass, "sink"), "sink"); + gst_element_add_pad (GST_ELEMENT (wavpackdec), wavpackdec->sinkpad); + + gst_pad_set_chain_function (wavpackdec->sinkpad, gst_wavpack_dec_chain); gst_pad_set_link_function (wavpackdec->sinkpad, gst_wavpack_dec_link); +#if 0 wavpackdec->wvcsinkpad = gst_pad_new_from_template (gst_element_class_get_pad_template (klass, "wvcsink"), "wvcsink"); gst_pad_set_link_function (wavpackdec->wvcsinkpad, gst_wavpack_dec_wvclink); + gst_element_add_pad (GST_ELEMENT (wavpackdec), wavpackdec->wvcsinkpad); +#endif + wavpackdec->srcpad = gst_pad_new_from_template (gst_element_class_get_pad_template (klass, "src"), "src"); - gst_pad_use_explicit_caps (wavpackdec->srcpad); + gst_pad_use_fixed_caps (wavpackdec->srcpad); gst_pad_set_query_function (wavpackdec->srcpad, gst_wavpack_dec_src_query); - gst_element_add_pad (GST_ELEMENT (wavpackdec), wavpackdec->sinkpad); gst_element_add_pad (GST_ELEMENT (wavpackdec), wavpackdec->srcpad); - gst_element_add_pad (GST_ELEMENT (wavpackdec), wavpackdec->wvcsinkpad); - gst_element_set_loop_function (GST_ELEMENT (wavpackdec), - gst_wavpack_dec_loop); wavpackdec->decodebuf = NULL; + wavpackdec->decodebuf_size = 0; wavpackdec->stream = (WavpackStream *) g_malloc0 (sizeof (WavpackStream)); wavpackdec->context = (WavpackContext *) g_malloc0 (sizeof (WavpackContext)); } @@ -246,6 +247,7 @@ gst_wavpack_dec_setup_context (GstWavpackDec * wavpackdec, guchar * data, { WavpackContext *context = wavpackdec->context; WavpackStream *stream = wavpackdec->stream; + guint buffer_size; memset (context, 0, sizeof (context)); @@ -267,6 +269,14 @@ gst_wavpack_dec_setup_context (GstWavpackDec * wavpackdec, guchar * data, context->wvc_flag = FALSE; } + buffer_size = + stream->wphdr.block_samples * wavpackdec->channels * sizeof (int32_t); + if (wavpackdec->decodebuf_size < buffer_size) { + wavpackdec->decodebuf = + (int32_t *) g_realloc (wavpackdec->decodebuf, buffer_size); + wavpackdec->decodebuf_size = buffer_size; + } + unpack_init (context); } @@ -317,71 +327,25 @@ gst_wavpack_dec_format_samples (GstWavpackDec * wavpackdec, int32_t * samples, return buf; } - -static void -gst_wavpack_dec_loop (GstElement * element) +static GstFlowReturn +gst_wavpack_dec_chain (GstPad * pad, GstBuffer * buf) { - GstWavpackDec *wavpackdec = GST_WAVPACK_DEC (element); - GstData *data, *cdata = NULL; - GstBuffer *buf, *outbuf, *cbuf = NULL; - - gboolean got_event = FALSE; - - if (!gst_pad_is_linked (wavpackdec->sinkpad)) { - return; - } - /* - if (!gst_pad_is_linked (wavpackdec->wvcsinkpad)) { - return; - } - */ - - data = gst_pad_pull (wavpackdec->sinkpad); - - if (GST_IS_EVENT (data)) { - GstEvent *event = GST_EVENT (data); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_EOS: - gst_event_unref (event); - gst_pad_push (wavpackdec->srcpad, - GST_DATA (gst_event_new (GST_EVENT_EOS))); - gst_element_set_eos (element); - break; - default: - gst_pad_event_default (wavpackdec->srcpad, event); - break; - } - got_event = TRUE; - } + GstWavpackDec *wavpackdec = GST_WAVPACK_DEC (gst_pad_get_parent (pad)); + GstBuffer *outbuf, *cbuf = NULL; + GstFlowReturn ret = GST_FLOW_OK; +#if 0 if (gst_pad_is_linked (wavpackdec->wvcsinkpad)) { - cdata = gst_pad_pull (wavpackdec->wvcsinkpad); - if (GST_IS_EVENT (cdata)) { - GstEvent *event = GST_EVENT (cdata); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_EOS: - gst_event_unref (event); - gst_pad_push (wavpackdec->srcpad, - GST_DATA (gst_event_new (GST_EVENT_EOS))); - gst_element_set_eos (element); - break; - default: - gst_pad_event_default (wavpackdec->srcpad, event); - break; - } - got_event = TRUE; + if (GST_FLOW_OK != gst_pad_pull_range (wavpackdec->wvcsinkpad, + wavpackdec->wvcflushed_bytes, -1, &cbuf)) { + cbuf = NULL; } else { - cbuf = GST_BUFFER (cdata); + wavpackdec->wvcflushed_bytes += GST_BUFFER_SIZE (cbuf); } - } - - if (got_event) - return; - buf = GST_BUFFER (data); + } +#endif gst_wavpack_dec_setup_context (wavpackdec, GST_BUFFER_DATA (buf), cbuf ? GST_BUFFER_DATA (cbuf) : NULL); @@ -393,9 +357,19 @@ gst_wavpack_dec_loop (GstElement * element) GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf); GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf); + gst_buffer_unref (buf); + if (cbuf) { + gst_buffer_unref (cbuf); + } + + gst_buffer_set_caps (outbuf, GST_PAD_CAPS (wavpackdec->srcpad)); + if (GST_FLOW_OK != (ret = gst_pad_push (wavpackdec->srcpad, outbuf))) { + gst_buffer_unref (outbuf); + } + + return ret; - gst_pad_push (wavpackdec->srcpad, GST_DATA (outbuf)); } gboolean diff --git a/ext/wavpack/gstwavpackdec.h b/ext/wavpack/gstwavpackdec.h index 32fc48d1..1f4a3835 100644 --- a/ext/wavpack/gstwavpackdec.h +++ b/ext/wavpack/gstwavpackdec.h @@ -48,11 +48,14 @@ struct _GstWavpackDec GstElement element; GstPad *sinkpad, *srcpad; +#if 0 GstPad *wvcsinkpad; +#endif WavpackContext *context; int32_t *decodebuf; + guint decodebuf_size; WavpackStream *stream; @@ -61,6 +64,10 @@ struct _GstWavpackDec guint width; long frame_length; + guint64 wvcflushed_bytes; + guint64 duration; + guint64 wvcduration; + guchar *decdata; long *cache; }; diff --git a/ext/wavpack/gstwavpackparse.c b/ext/wavpack/gstwavpackparse.c index 31468e26..4ba0bf52 100644 --- a/ext/wavpack/gstwavpackparse.c +++ b/ext/wavpack/gstwavpackparse.c @@ -69,10 +69,15 @@ static void gst_wavpack_parse_class_init (GstWavpackParseClass * klass); static void gst_wavpack_parse_base_init (GstWavpackParseClass * klass); static void gst_wavpack_parse_init (GstWavpackParse * wavpackparse); -static void gst_wavpack_parse_handle_event (GstElement * element); +static gboolean gst_wavepack_parse_sink_activate (GstPad * sinkpad); +static gboolean +gst_wavepack_parse_sink_activate_pull (GstPad * sinkpad, gboolean active); + +static gboolean gst_wavpack_parse_sink_event (GstPad * pad, GstEvent * event); + static void gst_wavpack_parse_loop (GstElement * element); -static GstElementStateReturn gst_wavpack_parse_change_state (GstElement * - element); +static GstStateChangeReturn gst_wavpack_parse_change_state (GstElement * + element, GstStateChange transition); static GstElementClass *parent = NULL; @@ -141,61 +146,97 @@ gst_wavpack_parse_class_init (GstWavpackParseClass * klass) } static gboolean -gst_wavpack_parse_src_query (GstPad * pad, GstQueryType type, - GstFormat * format, gint64 * value) +gst_wavpack_parse_src_query (GstPad * pad, GstQuery * query) { GstWavpackParse *wavpackparse = GST_WAVPACK_PARSE (gst_pad_get_parent (pad)); - - if ((type == GST_QUERY_TOTAL) && (*format == GST_FORMAT_TIME)) { - if (wavpackparse->total_samples == 0) { - *value = 0; - return FALSE; - } - *value = - ((gdouble) wavpackparse->total_samples / - (gdouble) wavpackparse->samplerate) * GST_SECOND; - return TRUE; - } else if ((type == GST_QUERY_POSITION) && (*format == GST_FORMAT_TIME)) { - *value = wavpackparse->timestamp; - return TRUE; - } else { - return gst_pad_query_default (pad, type, format, value); + GstFormat format = GST_FORMAT_DEFAULT; + gint64 value; + gboolean ret = FALSE; + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_POSITION: + gst_query_parse_position (query, &format, &value); + if (format == GST_FORMAT_TIME) { + value = wavpackparse->timestamp; + gst_query_set_duration (query, format, value); + g_object_unref (wavpackparse); + ret = TRUE; + break; + } + break; + case GST_QUERY_DURATION: + gst_query_parse_duration (query, &format, &value); + + if (format == GST_FORMAT_TIME) { + if (wavpackparse->total_samples == 0) { + value = 0; + gst_query_set_duration (query, format, value); + g_object_unref (wavpackparse); + ret = FALSE; + break; + } + value = ((gdouble) wavpackparse->total_samples / + (gdouble) wavpackparse->samplerate) * GST_SECOND; + gst_query_set_duration (query, format, value); + g_object_unref (wavpackparse); + ret = TRUE; + break; + } + break; + default: + g_object_unref (wavpackparse); + ret = gst_pad_query_default (pad, query); + break; } - return FALSE; + + return ret; + } static gboolean gst_wavpack_parse_src_event (GstPad * pad, GstEvent * event) { GstWavpackParse *wavpackparse; - GstSeekType method; + GstSeekType type; GstFormat format; gboolean need_flush; gint64 offset, dest; + GstSeekFlags flags; + gboolean ret = TRUE; wavpackparse = GST_WAVPACK_PARSE (gst_pad_get_parent (pad)); if (GST_EVENT_TYPE (event) != GST_EVENT_SEEK) { - return gst_pad_send_event (GST_PAD_PEER (wavpackparse->sinkpad), event); + GstPad *peer; + + if (!(peer = gst_pad_get_peer (wavpackparse->sinkpad))) { + ret = FALSE; + goto done; + } + ret = gst_pad_send_event (peer, event); + gst_object_unref (peer); + goto done; } - format = GST_EVENT_SEEK_FORMAT (event); - offset = GST_EVENT_SEEK_OFFSET (event); - method = GST_EVENT_SEEK_METHOD (event); - need_flush = GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH; + gst_event_parse_seek (event, NULL, &format, &flags, &type, &offset, NULL, + NULL); + + need_flush = flags & GST_SEEK_FLAG_FLUSH; - gst_data_unref (GST_DATA (event)); - event = NULL; - if (offset < 0 || method != GST_SEEK_METHOD_SET) - return FALSE; + + if (offset < 0 || type != GST_SEEK_TYPE_SET) { + ret = FALSE; + goto done; + } if (format == GST_FORMAT_TIME) { dest = offset * wavpackparse->samplerate / GST_SECOND; } else if (format == GST_FORMAT_DEFAULT) { dest = offset; } else { - return FALSE; + ret = FALSE; + goto done; } wavpackparse->need_discont = TRUE; @@ -204,50 +245,65 @@ gst_wavpack_parse_src_event (GstPad * pad, GstEvent * event) wavpackparse->seek_pending = TRUE; wavpackparse->seek_offset = dest; - return TRUE; +done: + gst_event_unref (event); + gst_object_unref (wavpackparse); + return ret; } #define BUFSIZE 4096 static guint64 -find_header (GstByteStream * bs, guint64 filepos, WavpackHeader * wphdr) +find_header (GstWavpackParse * wavpackparse, guint64 filepos, + WavpackHeader * wphdr) { guint64 pos = filepos; + gint read = 0; + GstBuffer *buf = NULL; - gst_bytestream_seek (bs, filepos, GST_SEEK_METHOD_SET); + while (TRUE) { + guint8 *cur; - while (1) { - guint8 *data, *cur; - gint read; - - read = gst_bytestream_peek_bytes (bs, &data, BUFSIZE); - while (read != BUFSIZE) { - guint remaining; - GstEvent *event = NULL; - - gst_bytestream_get_status (bs, &remaining, &event); - if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) { - gst_event_unref (event); - return gst_bytestream_length (bs); - } - gst_event_unref (event); - read = gst_bytestream_peek_bytes (bs, &data, BUFSIZE); - continue; + if (GST_FLOW_OK != gst_pad_pull_range (wavpackparse->sinkpad, + wavpackparse->flushed_bytes + filepos, BUFSIZE, &buf)) { + wavpackparse->eos = TRUE; + gst_pad_push_event (wavpackparse->srcpad, gst_event_new_eos ()); + return 0; + } + read = GST_BUFFER_SIZE (buf); + + if (read == 0) { + wavpackparse->eos = TRUE; + gst_pad_push_event (wavpackparse->srcpad, gst_event_new_eos ()); + gst_buffer_unref (buf); + return 0; } - cur = data; + + cur = GST_BUFFER_DATA (buf); do { if (cur[0] == 'w' && cur[1] == 'v' && cur[2] == 'p' && cur[3] == 'k') { gst_wavpack_read_header (wphdr, cur); - return pos + (cur - data); + pos += (cur - GST_BUFFER_DATA (buf)); + gst_buffer_unref (buf); + buf = NULL; + return pos; } cur++; - } while ((cur - data) < (BUFSIZE - sizeof (WavpackHeader))); - gst_bytestream_flush_fast (bs, BUFSIZE - sizeof (WavpackHeader)); + } while ((cur - GST_BUFFER_DATA (buf)) < + (BUFSIZE - sizeof (WavpackHeader))); + + wavpackparse->flushed_bytes += BUFSIZE - sizeof (WavpackHeader); + pos += BUFSIZE - sizeof (WavpackHeader); } /* never reached */ - return gst_bytestream_length (bs); + + if (buf) { + gst_buffer_unref (buf); + buf = NULL; + } + return wavpackparse->duration - wavpackparse->flushed_bytes; } /* find the position of sample in the input bytestream, adapted from the @@ -256,13 +312,14 @@ static guint64 find_sample (GstWavpackParse * wavpackparse, guint32 sample) { WavpackHeader wphdr; - guint64 file_pos1 = 0, file_pos2 = gst_bytestream_length (wavpackparse->bs); + guint64 file_pos1 = 0; + guint64 file_pos2 = wavpackparse->duration - wavpackparse->flushed_bytes; guint64 sample_pos1 = 0, sample_pos2 = wavpackparse->total_samples; double ratio = 0.96; int file_skip = 0; if (sample >= wavpackparse->total_samples) { - return gst_bytestream_length (wavpackparse->bs); + return wavpackparse->duration - wavpackparse->flushed_bytes; } while (1) { @@ -273,15 +330,15 @@ find_sample (GstWavpackParse * wavpackparse, guint32 sample) bytes_per_sample /= sample_pos2 - sample_pos1; seek_pos = file_pos1 + (file_skip ? 32 : 0); seek_pos += (guint64) (bytes_per_sample * (sample - sample_pos1) * ratio); - seek_pos = find_header (wavpackparse->bs, seek_pos, &wphdr); + seek_pos = find_header (wavpackparse, seek_pos, &wphdr); - if (seek_pos == gst_bytestream_length (wavpackparse->bs) + if (seek_pos == wavpackparse->duration - wavpackparse->flushed_bytes || seek_pos >= file_pos2) { if (ratio > 0.0) { if ((ratio -= 0.24) < 0.0) ratio = 0.0; } else { - return gst_bytestream_length (wavpackparse->bs); + return wavpackparse->duration - wavpackparse->flushed_bytes; } } else if (wphdr.block_index > sample) { sample_pos2 = wphdr.block_index; @@ -303,16 +360,13 @@ find_sample (GstWavpackParse * wavpackparse, guint32 sample) static void gst_wavpack_parse_seek (GstWavpackParse * wavpackparse) { - guint8 *data; + GstBuffer *buf; gint num; - guint remaining; WavpackHeader *header = g_malloc (sizeof (WavpackHeader)); guint64 offset = find_sample (wavpackparse, wavpackparse->seek_offset); - gst_bytestream_seek (wavpackparse->bs, offset, GST_SEEK_METHOD_SET); - - if (offset == gst_bytestream_length (wavpackparse->bs)) { + if (offset >= wavpackparse->duration - wavpackparse->flushed_bytes) { /* seek failed or went beyond the end, go EOS */ wavpackparse->timestamp = ((gdouble) wavpackparse->total_samples / @@ -320,29 +374,26 @@ gst_wavpack_parse_seek (GstWavpackParse * wavpackparse) return; } - num = - gst_bytestream_peek_bytes (wavpackparse->bs, &data, - sizeof (WavpackHeader)); - while (num != sizeof (WavpackHeader)) { - GstEvent *event = NULL; + if (GST_FLOW_OK != gst_pad_pull_range (wavpackparse->sinkpad, + wavpackparse->flushed_bytes + offset, sizeof (WavpackHeader), &buf)) { + wavpackparse->eos = TRUE; + gst_pad_push_event (wavpackparse->srcpad, gst_event_new_eos ()); + return; + } + num = GST_BUFFER_SIZE (buf); - gst_bytestream_get_status (wavpackparse->bs, &remaining, &event); - if (!event) { - return; - } - gst_event_unref (event); - num = - gst_bytestream_peek_bytes (wavpackparse->bs, &data, - sizeof (WavpackHeader)); - continue; + if (num != sizeof (WavpackHeader)) { + wavpackparse->eos = TRUE; + gst_pad_push_event (wavpackparse->srcpad, gst_event_new_eos ()); + return; } - gst_wavpack_read_header (header, data); - if (wavpackparse->need_flush) { - GstEvent *flush = gst_event_new (GST_EVENT_FLUSH); + gst_wavpack_read_header (header, GST_BUFFER_DATA (buf)); + gst_buffer_unref (buf); - gst_pad_push (wavpackparse->srcpad, GST_DATA (flush)); + if (wavpackparse->need_flush) { wavpackparse->need_flush = FALSE; + gst_pad_push_event (wavpackparse->srcpad, gst_event_new_flush_start ()); } wavpackparse->need_discont = TRUE; @@ -356,53 +407,62 @@ gst_wavpack_parse_init (GstWavpackParse * wavpackparse) { GstElementClass *klass = GST_ELEMENT_GET_CLASS (wavpackparse); + wavpackparse->duration = -1; + wavpackparse->flushed_bytes = -1; + wavpackparse->eos = FALSE; + wavpackparse->sinkpad = gst_pad_new_from_template (gst_element_class_get_pad_template (klass, "sink"), "sink"); + gst_pad_set_event_function (wavpackparse->sinkpad, + gst_wavpack_parse_sink_event); + gst_element_add_pad (GST_ELEMENT (wavpackparse), wavpackparse->sinkpad); - gst_element_set_loop_function (GST_ELEMENT (wavpackparse), - gst_wavpack_parse_loop); - GST_FLAG_SET (wavpackparse, GST_ELEMENT_EVENT_AWARE); + gst_pad_set_activate_function (wavpackparse->sinkpad, + gst_wavepack_parse_sink_activate); + + gst_pad_set_activatepull_function (wavpackparse->sinkpad, + gst_wavepack_parse_sink_activate_pull); + + wavpackparse->srcpad = NULL; + } -static void -gst_wavpack_parse_handle_event (GstElement * element) +static gboolean +gst_wavpack_parse_sink_event (GstPad * pad, GstEvent * event) { - GstWavpackParse *wavpackparse = GST_WAVPACK_PARSE (element); - GstEvent *event = NULL; - guint remaining; - - gst_bytestream_get_status (wavpackparse->bs, &remaining, &event); - if (event) { - if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) { - if (GST_IS_PAD (wavpackparse->srcpad) - && gst_pad_is_active (wavpackparse->srcpad)) - gst_pad_push (wavpackparse->srcpad, GST_DATA (event)); - gst_element_set_eos (element); - } else if (GST_EVENT_TYPE (event) == GST_EVENT_DISCONTINUOUS) { - if (GST_IS_PAD (wavpackparse->srcpad) - && gst_pad_is_active (wavpackparse->srcpad)) - gst_pad_event_default (wavpackparse->srcpad, event); - } else { - gst_event_unref (event); - } - } else { - GST_ELEMENT_ERROR (element, STREAM, DEMUX, ("couldn't read wavpack header"), - (NULL)); + GstWavpackParse *wavpackparse = GST_WAVPACK_PARSE (gst_pad_get_parent (pad)); + gboolean res = TRUE; + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_EOS: + wavpackparse->eos = TRUE; + /* fall through */ + default: + res = gst_pad_event_default (pad, event); + gst_object_unref (wavpackparse); + return res; + break; } + } static void gst_wavpack_parse_loop (GstElement * element) { GstWavpackParse *wavpackparse = GST_WAVPACK_PARSE (element); - guint8 *data; gint num; GstBuffer *buf; WavpackHeader *header = g_malloc (sizeof (WavpackHeader)); + GST_PAD_STREAM_LOCK (wavpackparse->sinkpad); + + if (wavpackparse->eos) { + goto done; + } + if (wavpackparse->seek_pending) { gst_wavpack_parse_seek (wavpackparse); wavpackparse->need_discont = TRUE; @@ -410,45 +470,68 @@ gst_wavpack_parse_loop (GstElement * element) } if (wavpackparse->need_discont) { - if (GST_IS_PAD (wavpackparse->srcpad) - && gst_pad_is_active (wavpackparse->srcpad)) - gst_pad_push (wavpackparse->srcpad, - GST_DATA (gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, - wavpackparse->timestamp, GST_FORMAT_UNDEFINED))); - wavpackparse->need_discont = FALSE; + if (GST_IS_PAD (wavpackparse->srcpad)) { + gst_pad_push_event (wavpackparse->srcpad, + gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, + wavpackparse->timestamp, GST_CLOCK_TIME_NONE, 0)); + + wavpackparse->need_discont = FALSE; + } + } + + if (GST_FLOW_OK != gst_pad_pull_range (wavpackparse->sinkpad, + wavpackparse->flushed_bytes, sizeof (WavpackHeader), &buf)) { + wavpackparse->eos = TRUE; + gst_pad_push_event (wavpackparse->srcpad, gst_event_new_eos ()); + goto done; } + num = GST_BUFFER_SIZE (buf); - num = - gst_bytestream_peek_bytes (wavpackparse->bs, &data, - sizeof (WavpackHeader)); if (num != sizeof (WavpackHeader)) { - gst_wavpack_parse_handle_event (element); - return; + gst_buffer_unref (buf); + wavpackparse->eos = TRUE; + gst_pad_push_event (wavpackparse->srcpad, gst_event_new_eos ()); + goto done; } - gst_wavpack_read_header (header, data); - num = gst_bytestream_peek_bytes (wavpackparse->bs, &data, header->ckSize + 8); + gst_wavpack_read_header (header, GST_BUFFER_DATA (buf)); + gst_buffer_unref (buf); + + if (GST_FLOW_OK != gst_pad_pull_range (wavpackparse->sinkpad, + wavpackparse->flushed_bytes, header->ckSize + 8, &buf)) { + wavpackparse->eos = TRUE; + gst_pad_push_event (wavpackparse->srcpad, gst_event_new_eos ()); + goto done; + } + num = GST_BUFFER_SIZE (buf); + if (num != header->ckSize + 8) { - gst_wavpack_parse_handle_event (element); - return; + gst_buffer_unref (buf); + wavpackparse->eos = TRUE; + gst_pad_push_event (wavpackparse->srcpad, gst_event_new_eos ()); + goto done; } if (!GST_IS_PAD (wavpackparse->srcpad)) { - guchar *bufptr = data + sizeof (WavpackHeader); + + guchar *bufptr = GST_BUFFER_DATA (buf) + sizeof (WavpackHeader); GstCaps *caps = NULL; WavpackMetadata meta; - while (read_metadata_buff (&meta, data, &bufptr)) { + while (read_metadata_buff (&meta, GST_BUFFER_DATA (buf), &bufptr)) { if (meta.id == ID_WVC_BITSTREAM) { caps = gst_caps_new_simple ("audio/x-wavpack-correction", "framed", G_TYPE_BOOLEAN, TRUE, NULL); + if (GST_IS_PAD (wavpackparse->srcpad)) { + gst_object_unref (wavpackparse->srcpad); + } wavpackparse->srcpad = gst_pad_new_from_template (gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (wavpackparse), "wvcsrc"), "wvcsrc"); } else if (meta.id == ID_RIFF_HEADER) { WaveHeader *wheader = g_malloc (sizeof (WaveHeader)); - // skip RiffChunkHeader and ChunkHeader + /* skip RiffChunkHeader and ChunkHeader */ g_memmove (wheader, meta.data + 20, sizeof (WaveHeader)); little_endian_to_native (wheader, WaveHeaderFormat); wavpackparse->samplerate = wheader->SampleRate; @@ -459,24 +542,44 @@ gst_wavpack_parse_loop (GstElement * element) "channels", G_TYPE_INT, wavpackparse->channels, "rate", G_TYPE_INT, wavpackparse->samplerate, "framed", G_TYPE_BOOLEAN, TRUE, NULL); + if (GST_IS_PAD (wavpackparse->srcpad)) { + gst_object_unref (wavpackparse->srcpad); + } wavpackparse->srcpad = gst_pad_new_from_template (gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (wavpackparse), "src"), "src"); } } - gst_pad_use_explicit_caps (wavpackparse->srcpad); + + if (!(caps && GST_IS_PAD (wavpackparse->srcpad))) { + gst_buffer_unref (buf); + goto done; + } + gst_pad_set_query_function (wavpackparse->srcpad, gst_wavpack_parse_src_query); gst_pad_set_event_function (wavpackparse->srcpad, gst_wavpack_parse_src_event); + + gst_pad_set_caps (wavpackparse->srcpad, caps); + gst_pad_use_fixed_caps (wavpackparse->srcpad); + gst_element_add_pad (GST_ELEMENT (wavpackparse), wavpackparse->srcpad); - gst_pad_set_explicit_caps (wavpackparse->srcpad, caps); } - buf = gst_buffer_new_and_alloc (header->ckSize + 8); - memcpy (GST_BUFFER_DATA (buf), data, header->ckSize + 8); - gst_bytestream_flush_fast (wavpackparse->bs, header->ckSize + 8); + if (wavpackparse->need_discont) { + if (GST_IS_PAD (wavpackparse->srcpad)) { + gst_pad_push_event (wavpackparse->srcpad, + gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, + wavpackparse->timestamp, GST_CLOCK_TIME_NONE, 0)); + + wavpackparse->need_discont = FALSE; + } + } + + wavpackparse->flushed_bytes += header->ckSize + 8; + wavpackparse->timestamp = ((gdouble) header->block_index / (gdouble) wavpackparse->samplerate) * GST_SECOND; @@ -484,38 +587,107 @@ gst_wavpack_parse_loop (GstElement * element) GST_BUFFER_DURATION (buf) = ((gdouble) header->block_samples / (gdouble) wavpackparse->samplerate) * GST_SECOND; - gst_pad_push (wavpackparse->srcpad, GST_DATA (buf)); + gst_buffer_set_caps (buf, GST_PAD_CAPS (wavpackparse->srcpad)); + + if (GST_FLOW_OK != gst_pad_push (wavpackparse->srcpad, buf)) { + gst_buffer_unref (buf); + } + +done: + GST_PAD_STREAM_UNLOCK (wavpackparse->sinkpad); + return; + } -static GstElementStateReturn -gst_wavpack_parse_change_state (GstElement * element) +static GstStateChangeReturn +gst_wavpack_parse_change_state (GstElement * element, GstStateChange transition) { GstWavpackParse *wavpackparse = GST_WAVPACK_PARSE (element); + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - switch (GST_STATE_TRANSITION (element)) { - case GST_STATE_READY_TO_PAUSED: + switch (transition) { + case GST_STATE_CHANGE_READY_TO_PAUSED: + wavpackparse->flushed_bytes = 0; wavpackparse->need_discont = TRUE; - wavpackparse->bs = gst_bytestream_new (wavpackparse->sinkpad); + wavpackparse->eos = FALSE; break; - case GST_STATE_PAUSED_TO_READY: - gst_bytestream_destroy (wavpackparse->bs); - wavpackparse->seek_pending = FALSE; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + { + GstQuery *query; + GstFormat format = GST_FORMAT_BYTES; + + query = gst_query_new_duration (GST_FORMAT_BYTES); + if (gst_pad_query (GST_PAD_PEER (wavpackparse->sinkpad), query)) { + + gst_query_parse_duration (query, &format, + (gint64 *) & wavpackparse->duration); + + if (format != GST_FORMAT_BYTES) { + wavpackparse->duration = -1; + ret = GST_STATE_CHANGE_FAILURE; + } + + } else { + wavpackparse->duration = -1; + ret = GST_STATE_CHANGE_FAILURE; + } + gst_query_unref (query); + } break; default: break; } if (GST_ELEMENT_CLASS (parent)->change_state) - return GST_ELEMENT_CLASS (parent)->change_state (element); + ret = GST_ELEMENT_CLASS (parent)->change_state (element, transition); + + switch (transition) { + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + wavpackparse->seek_pending = FALSE; + break; + default: + break; + } + + return ret; +} + + +static gboolean +gst_wavepack_parse_sink_activate (GstPad * sinkpad) +{ + + if (gst_pad_check_pull_range (sinkpad)) { + return gst_pad_activate_pull (sinkpad, TRUE); + } else { + return FALSE; + } +} + +static gboolean +gst_wavepack_parse_sink_activate_pull (GstPad * sinkpad, gboolean active) +{ + + gboolean result; - return GST_STATE_SUCCESS; + if (active) { + + result = gst_pad_start_task (sinkpad, + (GstTaskFunction) gst_wavpack_parse_loop, GST_PAD_PARENT (sinkpad)); + } else { + result = gst_pad_stop_task (sinkpad); + } + + return result; + + return TRUE; } gboolean gst_wavpack_parse_plugin_init (GstPlugin * plugin) { - if (!gst_library_load ("gstbytestream")) - return FALSE; if (!gst_element_register (plugin, "wavpackparse", GST_RANK_PRIMARY, GST_TYPE_WAVPACK_PARSE)) { diff --git a/ext/wavpack/gstwavpackparse.h b/ext/wavpack/gstwavpackparse.h index ef76ba0f..41bfe494 100644 --- a/ext/wavpack/gstwavpackparse.h +++ b/ext/wavpack/gstwavpackparse.h @@ -23,7 +23,6 @@ #define __GST_WAVPACK_PARSE_H__ #include <gst/gst.h> -#include <gst/bytestream/bytestream.h> G_BEGIN_DECLS @@ -48,17 +47,19 @@ struct _GstWavpackParse GstPad *sinkpad, *srcpad; - GstByteStream* bs; - guint32 samplerate; guint32 channels; guint32 total_samples; guint64 timestamp; + guint64 flushed_bytes; + guint64 duration; + guint64 seek_offset; gboolean seek_pending; gboolean need_discont; gboolean need_flush; + gboolean eos; }; struct _GstWavpackParseClass |