diff --git a/ChangeLog b/ChangeLog index 5277e17a66..d9519738f4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2005-11-25 Edgard Lima + + * 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 * ext/wavpack/Makefile.am: diff --git a/PORTED_09 b/PORTED_09 index 3db4c8ec1f..52de38f4fe 100644 --- a/PORTED_09 +++ b/PORTED_09 @@ -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 dc922ece5a..ce1fcea5bc 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 651664c828..f6fe9c8783 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 b2ca835eb4..6660a726d4 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 d9fa074c1f..de7e87fd27 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); - gst_pad_push (wavpackdec->srcpad, GST_DATA (outbuf)); + 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; + } gboolean diff --git a/ext/wavpack/gstwavpackdec.h b/ext/wavpack/gstwavpackdec.h index 32fc48d15c..1f4a383523 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 31468e2689..4ba0bf5210 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)); + GstFormat format = GST_FORMAT_DEFAULT; + gint64 value; + gboolean ret = FALSE; - 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); + 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); - gst_data_unref (GST_DATA (event)); - event = NULL; + need_flush = flags & GST_SEEK_FLAG_FLUSH; - 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; } - cur = data; + 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 = 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; - - 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 (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; } - gst_wavpack_read_header (header, data); + num = GST_BUFFER_SIZE (buf); + + if (num != sizeof (WavpackHeader)) { + wavpackparse->eos = TRUE; + gst_pad_push_event (wavpackparse->srcpad, gst_event_new_eos ()); + return; + } + + gst_wavpack_read_header (header, GST_BUFFER_DATA (buf)); + gst_buffer_unref (buf); if (wavpackparse->need_flush) { - GstEvent *flush = gst_event_new (GST_EVENT_FLUSH); - - gst_pad_push (wavpackparse->srcpad, GST_DATA (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_element_add_pad (GST_ELEMENT (wavpackparse), wavpackparse->sinkpad); - gst_element_set_loop_function (GST_ELEMENT (wavpackparse), - gst_wavpack_parse_loop); + gst_pad_set_event_function (wavpackparse->sinkpad, + gst_wavpack_parse_sink_event); + + gst_element_add_pad (GST_ELEMENT (wavpackparse), wavpackparse->sinkpad); + + 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; - GST_FLAG_SET (wavpackparse, GST_ELEMENT_EVENT_AWARE); } -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; + GstWavpackParse *wavpackparse = GST_WAVPACK_PARSE (gst_pad_get_parent (pad)); + gboolean res = TRUE; - 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)); + 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; + } } - num = - gst_bytestream_peek_bytes (wavpackparse->bs, &data, - sizeof (WavpackHeader)); + 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); + 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); - return GST_STATE_SUCCESS; + 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; + + 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 ef76ba0f08..41bfe494c6 100644 --- a/ext/wavpack/gstwavpackparse.h +++ b/ext/wavpack/gstwavpackparse.h @@ -23,7 +23,6 @@ #define __GST_WAVPACK_PARSE_H__ #include -#include 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