Wavpack ported to 0.9. No support for correction file yet.

Original commit message from CVS:
Wavpack ported to 0.9. No support for correction file yet.
This commit is contained in:
Edgard Lima 2005-11-25 19:58:19 +00:00
parent 584acf3952
commit b066913324
9 changed files with 422 additions and 237 deletions

View file

@ -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> 2005-11-25 Thomas Vander Stichele <thomas at apestaart dot org>
* ext/wavpack/Makefile.am: * ext/wavpack/Makefile.am:

View file

@ -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. 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): List of ported plugins (update when you commit a ported plugin):
wavpack (alima)
musepack (alima) musepack (alima)
ivorbis (alima) ivorbis (alima)
gsmdec (alima) gsmdec (alima)

View file

@ -418,6 +418,15 @@ GST_CHECK_FEATURE(SDL, [SDL plug-in], sdlvideosink, [
AM_PATH_SDL(, HAVE_SDL=yes, HAVE_SDL=no) 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 *** ivorbis ***
dnl AM_PATH_IVORBIS only takes two options dnl AM_PATH_IVORBIS only takes two options
translit(dnm, m, l) AM_CONDITIONAL(USE_IVORBIS, true) translit(dnm, m, l) AM_CONDITIONAL(USE_IVORBIS, true)
@ -518,6 +527,7 @@ ext/Makefile
ext/directfb/Makefile ext/directfb/Makefile
ext/faac/Makefile ext/faac/Makefile
ext/faad/Makefile ext/faad/Makefile
ext/wavpack/Makefile
ext/ivorbis/Makefile ext/ivorbis/Makefile
ext/gsm/Makefile ext/gsm/Makefile
ext/musepack/Makefile ext/musepack/Makefile

View file

@ -76,6 +76,12 @@ endif
HERMES_DIR= HERMES_DIR=
# endif # endif
if USE_WAVPACK
WAVPACK_DIR=wavpack
else
WAVPACK_DIR=
endif
if USE_IVORBIS if USE_IVORBIS
IVORBIS_DIR=ivorbis IVORBIS_DIR=ivorbis
else else
@ -231,4 +237,6 @@ DIST_SUBDIRS= \
musepack \ musepack \
sdl \ sdl \
directfb \ directfb \
musepack \
wavpack \
ivorbis ivorbis

View file

@ -1,10 +1,10 @@
plugin_LTLIBRARIES = libgstwavpack.la plugin_LTLIBRARIES = libgstwavpack.la
libgstwavpack_la_SOURCES = gstwavpack.c \ libgstwavpack_la_SOURCES = gstwavpack.c \
gstwavpackcommon.c \ gstwavpackcommon.c \
gstwavpackparse.c \ gstwavpackparse.c \
gstwavpackdec.c gstwavpackdec.c
libgstwavpack_la_CFLAGS = $(GST_CFLAGS) $(WAVPACK_CFLAGS) libgstwavpack_la_CFLAGS = $(GST_CFLAGS) $(WAVPACK_CFLAGS)
libgstwavpack_la_LIBADD = $(WAVPACK_LIBS) libgstwavpack_la_LIBADD = $(WAVPACK_LIBS)

View file

@ -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_base_init (GstWavpackDecClass * klass);
static void gst_wavpack_dec_init (GstWavpackDec * wavpackdec); 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 GstElementClass *parent = NULL;
static GstPadLinkReturn 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)); 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; GstCaps *srccaps;
gint bits; gint bits;
if (!gst_caps_is_fixed (caps)) if (!gst_caps_is_fixed (GST_PAD_CAPS (peer)))
return GST_PAD_LINK_DELAYED; return GST_PAD_LINK_REFUSED;
gst_structure_get_int (structure, "rate", gst_structure_get_int (structure, "rate",
(gint32 *) & wavpackdec->samplerate); (gint32 *) & wavpackdec->samplerate);
@ -114,24 +114,22 @@ gst_wavpack_dec_link (GstPad * pad, const GstCaps * caps)
"endianness", G_TYPE_INT, LITTLE_ENDIAN, "endianness", G_TYPE_INT, LITTLE_ENDIAN,
"buffer-frames", G_TYPE_INT, 0, NULL); "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; return GST_PAD_LINK_OK;
} }
#if 0
static GstPadLinkReturn 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)) if (!gst_caps_is_fixed (GST_PAD_CAPS (peer)))
return GST_PAD_LINK_DELAYED; return GST_PAD_LINK_REFUSED;
return GST_PAD_LINK_OK; return GST_PAD_LINK_OK;
} }
#endif
GType GType
gst_wavpack_dec_get_type (void) gst_wavpack_dec_get_type (void)
@ -201,10 +199,9 @@ gst_wavpack_dec_class_init (GstWavpackDecClass * klass)
} }
static gboolean static gboolean
gst_wavpack_dec_src_query (GstPad * pad, GstQueryType type, gst_wavpack_dec_src_query (GstPad * pad, GstQuery * query)
GstFormat * format, gint64 * value)
{ {
return gst_pad_query_default (pad, type, format, value); return gst_pad_query_default (pad, query);
} }
static void static void
@ -215,27 +212,31 @@ gst_wavpack_dec_init (GstWavpackDec * wavpackdec)
wavpackdec->sinkpad = wavpackdec->sinkpad =
gst_pad_new_from_template (gst_element_class_get_pad_template (klass, gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
"sink"), "sink"); "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); gst_pad_set_link_function (wavpackdec->sinkpad, gst_wavpack_dec_link);
#if 0
wavpackdec->wvcsinkpad = wavpackdec->wvcsinkpad =
gst_pad_new_from_template (gst_element_class_get_pad_template (klass, gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
"wvcsink"), "wvcsink"); "wvcsink"), "wvcsink");
gst_pad_set_link_function (wavpackdec->wvcsinkpad, gst_wavpack_dec_wvclink); gst_pad_set_link_function (wavpackdec->wvcsinkpad, gst_wavpack_dec_wvclink);
gst_element_add_pad (GST_ELEMENT (wavpackdec), wavpackdec->wvcsinkpad);
#endif
wavpackdec->srcpad = wavpackdec->srcpad =
gst_pad_new_from_template (gst_element_class_get_pad_template (klass, gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
"src"), "src"); "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_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->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 = NULL;
wavpackdec->decodebuf_size = 0;
wavpackdec->stream = (WavpackStream *) g_malloc0 (sizeof (WavpackStream)); wavpackdec->stream = (WavpackStream *) g_malloc0 (sizeof (WavpackStream));
wavpackdec->context = (WavpackContext *) g_malloc0 (sizeof (WavpackContext)); wavpackdec->context = (WavpackContext *) g_malloc0 (sizeof (WavpackContext));
} }
@ -246,6 +247,7 @@ gst_wavpack_dec_setup_context (GstWavpackDec * wavpackdec, guchar * data,
{ {
WavpackContext *context = wavpackdec->context; WavpackContext *context = wavpackdec->context;
WavpackStream *stream = wavpackdec->stream; WavpackStream *stream = wavpackdec->stream;
guint buffer_size;
memset (context, 0, sizeof (context)); memset (context, 0, sizeof (context));
@ -267,6 +269,14 @@ gst_wavpack_dec_setup_context (GstWavpackDec * wavpackdec, guchar * data,
context->wvc_flag = FALSE; 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); unpack_init (context);
} }
@ -317,71 +327,25 @@ gst_wavpack_dec_format_samples (GstWavpackDec * wavpackdec, int32_t * samples,
return buf; return buf;
} }
static GstFlowReturn
static void gst_wavpack_dec_chain (GstPad * pad, GstBuffer * buf)
gst_wavpack_dec_loop (GstElement * element)
{ {
GstWavpackDec *wavpackdec = GST_WAVPACK_DEC (element);
GstData *data, *cdata = NULL;
GstBuffer *buf, *outbuf, *cbuf = NULL;
gboolean got_event = FALSE; GstWavpackDec *wavpackdec = GST_WAVPACK_DEC (gst_pad_get_parent (pad));
GstBuffer *outbuf, *cbuf = NULL;
if (!gst_pad_is_linked (wavpackdec->sinkpad)) { GstFlowReturn ret = GST_FLOW_OK;
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;
}
#if 0
if (gst_pad_is_linked (wavpackdec->wvcsinkpad)) { if (gst_pad_is_linked (wavpackdec->wvcsinkpad)) {
cdata = gst_pad_pull (wavpackdec->wvcsinkpad); if (GST_FLOW_OK != gst_pad_pull_range (wavpackdec->wvcsinkpad,
if (GST_IS_EVENT (cdata)) { wavpackdec->wvcflushed_bytes, -1, &cbuf)) {
GstEvent *event = GST_EVENT (cdata); cbuf = NULL;
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;
} else { } else {
cbuf = GST_BUFFER (cdata); wavpackdec->wvcflushed_bytes += GST_BUFFER_SIZE (cbuf);
} }
} }
#endif
if (got_event)
return;
buf = GST_BUFFER (data);
gst_wavpack_dec_setup_context (wavpackdec, GST_BUFFER_DATA (buf), gst_wavpack_dec_setup_context (wavpackdec, GST_BUFFER_DATA (buf),
cbuf ? GST_BUFFER_DATA (cbuf) : NULL); 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_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (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 gboolean

View file

@ -48,11 +48,14 @@ struct _GstWavpackDec
GstElement element; GstElement element;
GstPad *sinkpad, *srcpad; GstPad *sinkpad, *srcpad;
#if 0
GstPad *wvcsinkpad; GstPad *wvcsinkpad;
#endif
WavpackContext *context; WavpackContext *context;
int32_t *decodebuf; int32_t *decodebuf;
guint decodebuf_size;
WavpackStream *stream; WavpackStream *stream;
@ -61,6 +64,10 @@ struct _GstWavpackDec
guint width; guint width;
long frame_length; long frame_length;
guint64 wvcflushed_bytes;
guint64 duration;
guint64 wvcduration;
guchar *decdata; guchar *decdata;
long *cache; long *cache;
}; };

View file

@ -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_base_init (GstWavpackParseClass * klass);
static void gst_wavpack_parse_init (GstWavpackParse * wavpackparse); 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 void gst_wavpack_parse_loop (GstElement * element);
static GstElementStateReturn gst_wavpack_parse_change_state (GstElement * static GstStateChangeReturn gst_wavpack_parse_change_state (GstElement *
element); element, GstStateChange transition);
static GstElementClass *parent = NULL; static GstElementClass *parent = NULL;
@ -141,61 +146,97 @@ gst_wavpack_parse_class_init (GstWavpackParseClass * klass)
} }
static gboolean static gboolean
gst_wavpack_parse_src_query (GstPad * pad, GstQueryType type, gst_wavpack_parse_src_query (GstPad * pad, GstQuery * query)
GstFormat * format, gint64 * value)
{ {
GstWavpackParse *wavpackparse = GST_WAVPACK_PARSE (gst_pad_get_parent (pad)); 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)) { switch (GST_QUERY_TYPE (query)) {
if (wavpackparse->total_samples == 0) { case GST_QUERY_POSITION:
*value = 0; gst_query_parse_position (query, &format, &value);
return FALSE; if (format == GST_FORMAT_TIME) {
} value = wavpackparse->timestamp;
*value = gst_query_set_duration (query, format, value);
((gdouble) wavpackparse->total_samples / g_object_unref (wavpackparse);
(gdouble) wavpackparse->samplerate) * GST_SECOND; ret = TRUE;
return TRUE; break;
} else if ((type == GST_QUERY_POSITION) && (*format == GST_FORMAT_TIME)) { }
*value = wavpackparse->timestamp; break;
return TRUE; case GST_QUERY_DURATION:
} else { gst_query_parse_duration (query, &format, &value);
return gst_pad_query_default (pad, type, 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 static gboolean
gst_wavpack_parse_src_event (GstPad * pad, GstEvent * event) gst_wavpack_parse_src_event (GstPad * pad, GstEvent * event)
{ {
GstWavpackParse *wavpackparse; GstWavpackParse *wavpackparse;
GstSeekType method; GstSeekType type;
GstFormat format; GstFormat format;
gboolean need_flush; gboolean need_flush;
gint64 offset, dest; gint64 offset, dest;
GstSeekFlags flags;
gboolean ret = TRUE;
wavpackparse = GST_WAVPACK_PARSE (gst_pad_get_parent (pad)); wavpackparse = GST_WAVPACK_PARSE (gst_pad_get_parent (pad));
if (GST_EVENT_TYPE (event) != GST_EVENT_SEEK) { 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); gst_event_parse_seek (event, NULL, &format, &flags, &type, &offset, NULL,
offset = GST_EVENT_SEEK_OFFSET (event); NULL);
method = GST_EVENT_SEEK_METHOD (event);
need_flush = GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH;
gst_data_unref (GST_DATA (event)); need_flush = flags & GST_SEEK_FLAG_FLUSH;
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) { if (format == GST_FORMAT_TIME) {
dest = offset * wavpackparse->samplerate / GST_SECOND; dest = offset * wavpackparse->samplerate / GST_SECOND;
} else if (format == GST_FORMAT_DEFAULT) { } else if (format == GST_FORMAT_DEFAULT) {
dest = offset; dest = offset;
} else { } else {
return FALSE; ret = FALSE;
goto done;
} }
wavpackparse->need_discont = TRUE; wavpackparse->need_discont = TRUE;
@ -204,50 +245,65 @@ gst_wavpack_parse_src_event (GstPad * pad, GstEvent * event)
wavpackparse->seek_pending = TRUE; wavpackparse->seek_pending = TRUE;
wavpackparse->seek_offset = dest; wavpackparse->seek_offset = dest;
return TRUE; done:
gst_event_unref (event);
gst_object_unref (wavpackparse);
return ret;
} }
#define BUFSIZE 4096 #define BUFSIZE 4096
static guint64 static guint64
find_header (GstByteStream * bs, guint64 filepos, WavpackHeader * wphdr) find_header (GstWavpackParse * wavpackparse, guint64 filepos,
WavpackHeader * wphdr)
{ {
guint64 pos = filepos; guint64 pos = filepos;
gint read = 0;
GstBuffer *buf = NULL;
gst_bytestream_seek (bs, filepos, GST_SEEK_METHOD_SET); while (TRUE) {
guint8 *cur;
while (1) { if (GST_FLOW_OK != gst_pad_pull_range (wavpackparse->sinkpad,
guint8 *data, *cur; wavpackparse->flushed_bytes + filepos, BUFSIZE, &buf)) {
gint read; wavpackparse->eos = TRUE;
gst_pad_push_event (wavpackparse->srcpad, gst_event_new_eos ());
read = gst_bytestream_peek_bytes (bs, &data, BUFSIZE); return 0;
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;
} }
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 { do {
if (cur[0] == 'w' && cur[1] == 'v' && cur[2] == 'p' && cur[3] == 'k') { if (cur[0] == 'w' && cur[1] == 'v' && cur[2] == 'p' && cur[3] == 'k') {
gst_wavpack_read_header (wphdr, cur); 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++; cur++;
} while ((cur - data) < (BUFSIZE - sizeof (WavpackHeader))); } while ((cur - GST_BUFFER_DATA (buf)) <
gst_bytestream_flush_fast (bs, BUFSIZE - sizeof (WavpackHeader)); (BUFSIZE - sizeof (WavpackHeader)));
wavpackparse->flushed_bytes += BUFSIZE - sizeof (WavpackHeader);
pos += BUFSIZE - sizeof (WavpackHeader); pos += BUFSIZE - sizeof (WavpackHeader);
} }
/* never reached */ /* 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 /* find the position of sample in the input bytestream, adapted from the
@ -256,13 +312,14 @@ static guint64
find_sample (GstWavpackParse * wavpackparse, guint32 sample) find_sample (GstWavpackParse * wavpackparse, guint32 sample)
{ {
WavpackHeader wphdr; 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; guint64 sample_pos1 = 0, sample_pos2 = wavpackparse->total_samples;
double ratio = 0.96; double ratio = 0.96;
int file_skip = 0; int file_skip = 0;
if (sample >= wavpackparse->total_samples) { if (sample >= wavpackparse->total_samples) {
return gst_bytestream_length (wavpackparse->bs); return wavpackparse->duration - wavpackparse->flushed_bytes;
} }
while (1) { while (1) {
@ -273,15 +330,15 @@ find_sample (GstWavpackParse * wavpackparse, guint32 sample)
bytes_per_sample /= sample_pos2 - sample_pos1; bytes_per_sample /= sample_pos2 - sample_pos1;
seek_pos = file_pos1 + (file_skip ? 32 : 0); seek_pos = file_pos1 + (file_skip ? 32 : 0);
seek_pos += (guint64) (bytes_per_sample * (sample - sample_pos1) * ratio); 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) { || seek_pos >= file_pos2) {
if (ratio > 0.0) { if (ratio > 0.0) {
if ((ratio -= 0.24) < 0.0) if ((ratio -= 0.24) < 0.0)
ratio = 0.0; ratio = 0.0;
} else { } else {
return gst_bytestream_length (wavpackparse->bs); return wavpackparse->duration - wavpackparse->flushed_bytes;
} }
} else if (wphdr.block_index > sample) { } else if (wphdr.block_index > sample) {
sample_pos2 = wphdr.block_index; sample_pos2 = wphdr.block_index;
@ -303,16 +360,13 @@ find_sample (GstWavpackParse * wavpackparse, guint32 sample)
static void static void
gst_wavpack_parse_seek (GstWavpackParse * wavpackparse) gst_wavpack_parse_seek (GstWavpackParse * wavpackparse)
{ {
guint8 *data; GstBuffer *buf;
gint num; gint num;
guint remaining;
WavpackHeader *header = g_malloc (sizeof (WavpackHeader)); WavpackHeader *header = g_malloc (sizeof (WavpackHeader));
guint64 offset = find_sample (wavpackparse, wavpackparse->seek_offset); guint64 offset = find_sample (wavpackparse, wavpackparse->seek_offset);
gst_bytestream_seek (wavpackparse->bs, offset, GST_SEEK_METHOD_SET); if (offset >= wavpackparse->duration - wavpackparse->flushed_bytes) {
if (offset == gst_bytestream_length (wavpackparse->bs)) {
/* seek failed or went beyond the end, go EOS */ /* seek failed or went beyond the end, go EOS */
wavpackparse->timestamp = wavpackparse->timestamp =
((gdouble) wavpackparse->total_samples / ((gdouble) wavpackparse->total_samples /
@ -320,29 +374,26 @@ gst_wavpack_parse_seek (GstWavpackParse * wavpackparse)
return; return;
} }
num = if (GST_FLOW_OK != gst_pad_pull_range (wavpackparse->sinkpad,
gst_bytestream_peek_bytes (wavpackparse->bs, &data, wavpackparse->flushed_bytes + offset, sizeof (WavpackHeader), &buf)) {
sizeof (WavpackHeader)); wavpackparse->eos = TRUE;
while (num != sizeof (WavpackHeader)) { gst_pad_push_event (wavpackparse->srcpad, gst_event_new_eos ());
GstEvent *event = NULL; return;
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;
} }
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) { if (wavpackparse->need_flush) {
GstEvent *flush = gst_event_new (GST_EVENT_FLUSH);
gst_pad_push (wavpackparse->srcpad, GST_DATA (flush));
wavpackparse->need_flush = FALSE; wavpackparse->need_flush = FALSE;
gst_pad_push_event (wavpackparse->srcpad, gst_event_new_flush_start ());
} }
wavpackparse->need_discont = TRUE; wavpackparse->need_discont = TRUE;
@ -356,53 +407,62 @@ gst_wavpack_parse_init (GstWavpackParse * wavpackparse)
{ {
GstElementClass *klass = GST_ELEMENT_GET_CLASS (wavpackparse); GstElementClass *klass = GST_ELEMENT_GET_CLASS (wavpackparse);
wavpackparse->duration = -1;
wavpackparse->flushed_bytes = -1;
wavpackparse->eos = FALSE;
wavpackparse->sinkpad = wavpackparse->sinkpad =
gst_pad_new_from_template (gst_element_class_get_pad_template (klass, gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
"sink"), "sink"); "sink"), "sink");
gst_element_add_pad (GST_ELEMENT (wavpackparse), wavpackparse->sinkpad); gst_pad_set_event_function (wavpackparse->sinkpad,
gst_element_set_loop_function (GST_ELEMENT (wavpackparse), gst_wavpack_parse_sink_event);
gst_wavpack_parse_loop);
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 static gboolean
gst_wavpack_parse_handle_event (GstElement * element) gst_wavpack_parse_sink_event (GstPad * pad, GstEvent * event)
{ {
GstWavpackParse *wavpackparse = GST_WAVPACK_PARSE (element); GstWavpackParse *wavpackparse = GST_WAVPACK_PARSE (gst_pad_get_parent (pad));
GstEvent *event = NULL; gboolean res = TRUE;
guint remaining;
gst_bytestream_get_status (wavpackparse->bs, &remaining, &event); switch (GST_EVENT_TYPE (event)) {
if (event) { case GST_EVENT_EOS:
if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) { wavpackparse->eos = TRUE;
if (GST_IS_PAD (wavpackparse->srcpad) /* fall through */
&& gst_pad_is_active (wavpackparse->srcpad)) default:
gst_pad_push (wavpackparse->srcpad, GST_DATA (event)); res = gst_pad_event_default (pad, event);
gst_element_set_eos (element); gst_object_unref (wavpackparse);
} else if (GST_EVENT_TYPE (event) == GST_EVENT_DISCONTINUOUS) { return res;
if (GST_IS_PAD (wavpackparse->srcpad) break;
&& 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));
} }
} }
static void static void
gst_wavpack_parse_loop (GstElement * element) gst_wavpack_parse_loop (GstElement * element)
{ {
GstWavpackParse *wavpackparse = GST_WAVPACK_PARSE (element); GstWavpackParse *wavpackparse = GST_WAVPACK_PARSE (element);
guint8 *data;
gint num; gint num;
GstBuffer *buf; GstBuffer *buf;
WavpackHeader *header = g_malloc (sizeof (WavpackHeader)); WavpackHeader *header = g_malloc (sizeof (WavpackHeader));
GST_PAD_STREAM_LOCK (wavpackparse->sinkpad);
if (wavpackparse->eos) {
goto done;
}
if (wavpackparse->seek_pending) { if (wavpackparse->seek_pending) {
gst_wavpack_parse_seek (wavpackparse); gst_wavpack_parse_seek (wavpackparse);
wavpackparse->need_discont = TRUE; wavpackparse->need_discont = TRUE;
@ -410,45 +470,68 @@ gst_wavpack_parse_loop (GstElement * element)
} }
if (wavpackparse->need_discont) { if (wavpackparse->need_discont) {
if (GST_IS_PAD (wavpackparse->srcpad) if (GST_IS_PAD (wavpackparse->srcpad)) {
&& gst_pad_is_active (wavpackparse->srcpad)) gst_pad_push_event (wavpackparse->srcpad,
gst_pad_push (wavpackparse->srcpad, gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
GST_DATA (gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, wavpackparse->timestamp, GST_CLOCK_TIME_NONE, 0));
wavpackparse->timestamp, GST_FORMAT_UNDEFINED)));
wavpackparse->need_discont = FALSE; wavpackparse->need_discont = FALSE;
}
} }
num = if (GST_FLOW_OK != gst_pad_pull_range (wavpackparse->sinkpad,
gst_bytestream_peek_bytes (wavpackparse->bs, &data, wavpackparse->flushed_bytes, sizeof (WavpackHeader), &buf)) {
sizeof (WavpackHeader)); wavpackparse->eos = TRUE;
gst_pad_push_event (wavpackparse->srcpad, gst_event_new_eos ());
goto done;
}
num = GST_BUFFER_SIZE (buf);
if (num != sizeof (WavpackHeader)) { if (num != sizeof (WavpackHeader)) {
gst_wavpack_parse_handle_event (element); gst_buffer_unref (buf);
return; 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) { if (num != header->ckSize + 8) {
gst_wavpack_parse_handle_event (element); gst_buffer_unref (buf);
return; wavpackparse->eos = TRUE;
gst_pad_push_event (wavpackparse->srcpad, gst_event_new_eos ());
goto done;
} }
if (!GST_IS_PAD (wavpackparse->srcpad)) { if (!GST_IS_PAD (wavpackparse->srcpad)) {
guchar *bufptr = data + sizeof (WavpackHeader);
guchar *bufptr = GST_BUFFER_DATA (buf) + sizeof (WavpackHeader);
GstCaps *caps = NULL; GstCaps *caps = NULL;
WavpackMetadata meta; 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) { if (meta.id == ID_WVC_BITSTREAM) {
caps = gst_caps_new_simple ("audio/x-wavpack-correction", caps = gst_caps_new_simple ("audio/x-wavpack-correction",
"framed", G_TYPE_BOOLEAN, TRUE, NULL); "framed", G_TYPE_BOOLEAN, TRUE, NULL);
if (GST_IS_PAD (wavpackparse->srcpad)) {
gst_object_unref (wavpackparse->srcpad);
}
wavpackparse->srcpad = wavpackparse->srcpad =
gst_pad_new_from_template (gst_element_class_get_pad_template gst_pad_new_from_template (gst_element_class_get_pad_template
(GST_ELEMENT_GET_CLASS (wavpackparse), "wvcsrc"), "wvcsrc"); (GST_ELEMENT_GET_CLASS (wavpackparse), "wvcsrc"), "wvcsrc");
} else if (meta.id == ID_RIFF_HEADER) { } else if (meta.id == ID_RIFF_HEADER) {
WaveHeader *wheader = g_malloc (sizeof (WaveHeader)); WaveHeader *wheader = g_malloc (sizeof (WaveHeader));
// skip RiffChunkHeader and ChunkHeader /* skip RiffChunkHeader and ChunkHeader */
g_memmove (wheader, meta.data + 20, sizeof (WaveHeader)); g_memmove (wheader, meta.data + 20, sizeof (WaveHeader));
little_endian_to_native (wheader, WaveHeaderFormat); little_endian_to_native (wheader, WaveHeaderFormat);
wavpackparse->samplerate = wheader->SampleRate; wavpackparse->samplerate = wheader->SampleRate;
@ -459,24 +542,44 @@ gst_wavpack_parse_loop (GstElement * element)
"channels", G_TYPE_INT, wavpackparse->channels, "channels", G_TYPE_INT, wavpackparse->channels,
"rate", G_TYPE_INT, wavpackparse->samplerate, "rate", G_TYPE_INT, wavpackparse->samplerate,
"framed", G_TYPE_BOOLEAN, TRUE, NULL); "framed", G_TYPE_BOOLEAN, TRUE, NULL);
if (GST_IS_PAD (wavpackparse->srcpad)) {
gst_object_unref (wavpackparse->srcpad);
}
wavpackparse->srcpad = wavpackparse->srcpad =
gst_pad_new_from_template (gst_element_class_get_pad_template gst_pad_new_from_template (gst_element_class_get_pad_template
(GST_ELEMENT_GET_CLASS (wavpackparse), "src"), "src"); (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_pad_set_query_function (wavpackparse->srcpad,
gst_wavpack_parse_src_query); gst_wavpack_parse_src_query);
gst_pad_set_event_function (wavpackparse->srcpad, gst_pad_set_event_function (wavpackparse->srcpad,
gst_wavpack_parse_src_event); 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_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); if (wavpackparse->need_discont) {
memcpy (GST_BUFFER_DATA (buf), data, header->ckSize + 8); if (GST_IS_PAD (wavpackparse->srcpad)) {
gst_bytestream_flush_fast (wavpackparse->bs, header->ckSize + 8); 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 = wavpackparse->timestamp =
((gdouble) header->block_index / (gdouble) wavpackparse->samplerate) * ((gdouble) header->block_index / (gdouble) wavpackparse->samplerate) *
GST_SECOND; GST_SECOND;
@ -484,38 +587,107 @@ gst_wavpack_parse_loop (GstElement * element)
GST_BUFFER_DURATION (buf) = GST_BUFFER_DURATION (buf) =
((gdouble) header->block_samples / (gdouble) wavpackparse->samplerate) * ((gdouble) header->block_samples / (gdouble) wavpackparse->samplerate) *
GST_SECOND; 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 static GstStateChangeReturn
gst_wavpack_parse_change_state (GstElement * element) gst_wavpack_parse_change_state (GstElement * element, GstStateChange transition)
{ {
GstWavpackParse *wavpackparse = GST_WAVPACK_PARSE (element); GstWavpackParse *wavpackparse = GST_WAVPACK_PARSE (element);
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
switch (GST_STATE_TRANSITION (element)) { switch (transition) {
case GST_STATE_READY_TO_PAUSED: case GST_STATE_CHANGE_READY_TO_PAUSED:
wavpackparse->flushed_bytes = 0;
wavpackparse->need_discont = TRUE; wavpackparse->need_discont = TRUE;
wavpackparse->bs = gst_bytestream_new (wavpackparse->sinkpad); wavpackparse->eos = FALSE;
break; break;
case GST_STATE_PAUSED_TO_READY: case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
gst_bytestream_destroy (wavpackparse->bs); {
wavpackparse->seek_pending = FALSE; 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; break;
default: default:
break; break;
} }
if (GST_ELEMENT_CLASS (parent)->change_state) 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 gboolean
gst_wavpack_parse_plugin_init (GstPlugin * plugin) gst_wavpack_parse_plugin_init (GstPlugin * plugin)
{ {
if (!gst_library_load ("gstbytestream"))
return FALSE;
if (!gst_element_register (plugin, "wavpackparse", if (!gst_element_register (plugin, "wavpackparse",
GST_RANK_PRIMARY, GST_TYPE_WAVPACK_PARSE)) { GST_RANK_PRIMARY, GST_TYPE_WAVPACK_PARSE)) {

View file

@ -23,7 +23,6 @@
#define __GST_WAVPACK_PARSE_H__ #define __GST_WAVPACK_PARSE_H__
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/bytestream/bytestream.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -48,17 +47,19 @@ struct _GstWavpackParse
GstPad *sinkpad, *srcpad; GstPad *sinkpad, *srcpad;
GstByteStream* bs;
guint32 samplerate; guint32 samplerate;
guint32 channels; guint32 channels;
guint32 total_samples; guint32 total_samples;
guint64 timestamp; guint64 timestamp;
guint64 flushed_bytes;
guint64 duration;
guint64 seek_offset; guint64 seek_offset;
gboolean seek_pending; gboolean seek_pending;
gboolean need_discont; gboolean need_discont;
gboolean need_flush; gboolean need_flush;
gboolean eos;
}; };
struct _GstWavpackParseClass struct _GstWavpackParseClass