summaryrefslogtreecommitdiff
path: root/ext/musepack
diff options
context:
space:
mode:
authorTim-Philipp Müller <tim@centricular.net>2006-01-24 21:33:25 +0000
committerTim-Philipp Müller <tim@centricular.net>2006-01-24 21:33:25 +0000
commitb92a9c4e2bbd81abe0d90cb31efb926f4e696fc2 (patch)
tree1b31881507183265d775d0512f392fcd45947c31 /ext/musepack
parent883bcdafbbd4552cfc2cfa1f96c5b0b807e42037 (diff)
ext/musepack/: Fix seeking in musepack files (it's still incredibly slow, but I don't think that is our plugin's faul...
Original commit message from CVS: * ext/musepack/gstmusepackdec.c: (gst_musepackdec_base_init), (gst_musepackdec_class_init), (gst_musepackdec_init), (gst_musepackdec_send_newsegment), (gst_musepackdec_handle_seek_event), (gst_musepackdec_src_event), (gst_musepackdec_src_query), (gst_musepackdec_src_convert), (gst_musepack_stream_init), (gst_musepackdec_sink_activate_pull), (gst_musepackdec_loop), (gst_musepackdec_change_state): * ext/musepack/gstmusepackdec.h: * ext/musepack/gstmusepackreader.c: (gst_musepack_reader_peek), (gst_musepack_reader_seek), (gst_musepack_reader_tell), (gst_musepack_reader_get_size): * ext/musepack/gstmusepackreader.h: Fix seeking in musepack files (it's still incredibly slow, but I don't think that is our plugin's fault). Clean up code and get rid of old cruft. Post tags with all kind of neat information like replay gain and such on the bus, if it is available. Add a 'musepackdec' debug category.
Diffstat (limited to 'ext/musepack')
-rw-r--r--ext/musepack/gstmusepackdec.c486
-rw-r--r--ext/musepack/gstmusepackdec.h22
-rw-r--r--ext/musepack/gstmusepackreader.c159
-rw-r--r--ext/musepack/gstmusepackreader.h1
4 files changed, 340 insertions, 328 deletions
diff --git a/ext/musepack/gstmusepackdec.c b/ext/musepack/gstmusepackdec.c
index 2216b5918..9a32c1c8e 100644
--- a/ext/musepack/gstmusepackdec.c
+++ b/ext/musepack/gstmusepackdec.c
@@ -1,5 +1,6 @@
/* GStreamer Musepack decoder plugin
* Copyright (C) 2004 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -24,6 +25,9 @@
#include "gstmusepackdec.h"
#include "gstmusepackreader.h"
+GST_DEBUG_CATEGORY (musepackdec_debug);
+#define GST_CAT_DEFAULT musepackdec_debug
+
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
@@ -39,8 +43,7 @@ static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
#else
#define BASE_CAPS \
"audio/x-raw-float, " \
- "width = (int) 32, " \
- "buffer-frames = (int) 0"
+ "width = (int) 32"
#endif
static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
@@ -51,16 +54,14 @@ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
"rate = (int) [ 8000, 96000 ], " "channels = (int) [ 1, 2 ]")
);
-static void gst_musepackdec_base_init (GstMusepackDecClass * klass);
-static void gst_musepackdec_class_init (GstMusepackDecClass * klass);
-static void gst_musepackdec_init (GstMusepackDec * musepackdec);
static void gst_musepackdec_dispose (GObject * obj);
static gboolean gst_musepackdec_src_event (GstPad * pad, GstEvent * event);
static const GstQueryType *gst_musepackdec_get_src_query_types (GstPad * pad);
static gboolean gst_musepackdec_src_query (GstPad * pad, GstQuery * query);
-
-static gboolean gst_musepackdec_sink_event (GstPad * pad, GstEvent * event);
+static gboolean gst_musepackdec_src_convert (GstPad * pad,
+ GstFormat src_format, gint64 src_value, GstFormat * dest_format,
+ gint64 * dest_value);
static gboolean gst_musepackdec_sink_activate (GstPad * sinkpad);
static gboolean
gst_musepackdec_sink_activate_pull (GstPad * sinkpad, gboolean active);
@@ -69,37 +70,9 @@ static void gst_musepackdec_loop (GstPad * sinkpad);
static GstStateChangeReturn
gst_musepackdec_change_state (GstElement * element, GstStateChange transition);
-static GstElementClass *parent_class = NULL;
+GST_BOILERPLATE (GstMusepackDec, gst_musepackdec, GstElement, GST_TYPE_ELEMENT)
-/* static guint gst_musepackdec_signals[LAST_SIGNAL] = { 0 }; */
-
-GType
-gst_musepackdec_get_type (void)
-{
- static GType gst_musepackdec_type = 0;
-
- if (!gst_musepackdec_type) {
- static const GTypeInfo gst_musepackdec_info = {
- sizeof (GstMusepackDecClass),
- (GBaseInitFunc) gst_musepackdec_base_init,
- NULL,
- (GClassInitFunc) gst_musepackdec_class_init,
- NULL,
- NULL,
- sizeof (GstMusepackDec),
- 0,
- (GInstanceInitFunc) gst_musepackdec_init,
- };
-
- gst_musepackdec_type = g_type_register_static (GST_TYPE_ELEMENT,
- "GstMusepackDec", &gst_musepackdec_info, (GTypeFlags) 0);
- }
-
- return gst_musepackdec_type;
-}
-
-static void
-gst_musepackdec_base_init (GstMusepackDecClass * klass)
+ static void gst_musepackdec_base_init (gpointer klass)
{
static GstElementDetails gst_musepackdec_details =
GST_ELEMENT_DETAILS ("Musepack decoder",
@@ -114,34 +87,31 @@ gst_musepackdec_base_init (GstMusepackDecClass * klass)
gst_static_pad_template_get (&sink_template));
gst_element_class_set_details (element_class, &gst_musepackdec_details);
+
+ GST_DEBUG_CATEGORY_INIT (musepackdec_debug, "musepackdec", 0, "mpc decoder");
}
static void
gst_musepackdec_class_init (GstMusepackDecClass * klass)
{
- parent_class = GST_ELEMENT_CLASS (g_type_class_ref (GST_TYPE_ELEMENT));
+ GST_ELEMENT_CLASS (klass)->change_state =
+ GST_DEBUG_FUNCPTR (gst_musepackdec_change_state);
- GST_ELEMENT_CLASS (klass)->change_state = gst_musepackdec_change_state;
- G_OBJECT_CLASS (klass)->dispose = gst_musepackdec_dispose;
+ G_OBJECT_CLASS (klass)->dispose = GST_DEBUG_FUNCPTR (gst_musepackdec_dispose);
}
static void
-gst_musepackdec_init (GstMusepackDec * musepackdec)
+gst_musepackdec_init (GstMusepackDec * musepackdec, GstMusepackDecClass * klass)
{
musepackdec->offset = 0;
musepackdec->r = g_new (mpc_reader, 1);
musepackdec->d = g_new (mpc_decoder, 1);
musepackdec->init = FALSE;
- musepackdec->seek_pending = FALSE;
- musepackdec->flush_pending = FALSE;
- musepackdec->eos = FALSE;
musepackdec->sinkpad =
gst_pad_new_from_template (gst_static_pad_template_get (&sink_template),
"sink");
- gst_pad_set_event_function (musepackdec->sinkpad,
- GST_DEBUG_FUNCPTR (gst_musepackdec_sink_event));
gst_element_add_pad (GST_ELEMENT (musepackdec), musepackdec->sinkpad);
gst_pad_set_activate_function (musepackdec->sinkpad,
@@ -161,8 +131,6 @@ gst_musepackdec_init (GstMusepackDec * musepackdec)
GST_DEBUG_FUNCPTR (gst_musepackdec_get_src_query_types));
gst_pad_use_fixed_caps (musepackdec->srcpad);
gst_element_add_pad (GST_ELEMENT (musepackdec), musepackdec->srcpad);
-
-
}
static void
@@ -178,116 +146,187 @@ gst_musepackdec_dispose (GObject * obj)
G_OBJECT_CLASS (parent_class)->dispose (obj);
}
-static gboolean
-gst_musepackdec_sink_event (GstPad * pad, GstEvent * event)
+static void
+gst_musepackdec_send_newsegment (GstMusepackDec * dec, gboolean update)
{
- GstMusepackDec *musepackdec = GST_MUSEPACK_DEC (gst_pad_get_parent (pad));
- gboolean res = TRUE;
+ GstSegment *s = &dec->segment;
+ GstFormat target_format = GST_FORMAT_TIME;
+ gint64 stop_time = GST_CLOCK_TIME_NONE;
+ gint64 start_time = 0;
+
+ /* segment is in DEFAULT format, but we want to send a TIME newsegment */
+ if (!gst_musepackdec_src_convert (dec->srcpad, GST_FORMAT_DEFAULT,
+ s->start, &target_format, &start_time)) {
+ GST_WARNING_OBJECT (dec, "failed to convert segment start %"
+ G_GINT64_FORMAT " to TIME", s->start);
+ return;
+ }
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_FLUSH_START:
- musepackdec->flush_pending = TRUE;
- goto done;
- break;
- case GST_EVENT_NEWSEGMENT:
- musepackdec->flush_pending = TRUE;
- musepackdec->seek_pending = TRUE;
- goto done;
- break;
- case GST_EVENT_EOS:
- musepackdec->eos = TRUE;
- /* fall through */
- default:
- res = gst_pad_event_default (pad, event);
- gst_object_unref (musepackdec);
- return res;
- break;
+ if (s->stop != -1 && !gst_musepackdec_src_convert (dec->srcpad,
+ GST_FORMAT_DEFAULT, s->stop, &target_format, &stop_time)) {
+ GST_WARNING_OBJECT (dec, "failed to convert segment stop to TIME");
+ return;
}
-done:
- gst_event_unref (event);
- gst_object_unref (musepackdec);
- return res;
+ GST_DEBUG_OBJECT (dec, "sending newsegment from %" GST_TIME_FORMAT
+ " to %" GST_TIME_FORMAT, GST_TIME_ARGS (start_time),
+ GST_TIME_ARGS (stop_time));
+ gst_pad_push_event (dec->srcpad,
+ gst_event_new_new_segment (update, s->rate, GST_FORMAT_TIME,
+ start_time, stop_time, start_time));
}
-
static gboolean
-gst_musepackdec_src_event (GstPad * pad, GstEvent * event)
+gst_musepackdec_handle_seek_event (GstMusepackDec * dec, GstEvent * event)
{
- GstMusepackDec *musepackdec = GST_MUSEPACK_DEC (gst_pad_get_parent (pad));
- gboolean res;
+ GstSeekType start_type, stop_type;
+ GstSeekFlags flags;
+ GstSegment segment;
+ GstFormat format;
+ gboolean only_update;
+ gboolean seek_ok;
+ gboolean flush;
+ gdouble rate;
+ gint64 start, stop;
+
+ gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start,
+ &stop_type, &stop);
+
+ if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT) {
+ GST_DEBUG_OBJECT (dec, "seek failed: only TIME or DEFAULT format allowed");
+ return FALSE;
+ }
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_SEEK:{
+ GST_OBJECT_LOCK (dec);
- gdouble rate;
- GstFormat format;
- GstSeekFlags flags;
- GstSeekType cur_type;
- gint64 cur;
- GstSeekType stop_type;
- gint64 stop;
+ if (format == GST_FORMAT_TIME) {
+ format = GST_FORMAT_DEFAULT;
+ if (start_type != GST_SEEK_TYPE_NONE &&
+ !gst_musepackdec_src_convert (dec->srcpad, GST_FORMAT_TIME,
+ start, &format, &start)) {
+ GST_DEBUG_OBJECT (dec, "failed to convert start to to DEFAULT format");
+ goto failed;
+ }
+ if (stop_type != GST_SEEK_TYPE_NONE &&
+ !gst_musepackdec_src_convert (dec->srcpad, GST_FORMAT_TIME,
+ stop, &format, &stop)) {
+ GST_DEBUG_OBJECT (dec, "failed to convert stop to to DEFAULT format");
+ goto failed;
+ }
+ }
- gst_event_parse_seek (event, &rate, &format, &flags,
- &cur_type, &cur, &stop_type, &stop);
+ flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
+ /* operate on segment copy until we know the seek worked */
+ segment = dec->segment;
+ GST_OBJECT_UNLOCK (dec);
- gint64 offset, len, pos;
- GstFormat fmt = GST_FORMAT_TIME;
+ gst_segment_set_seek (&segment, rate, GST_FORMAT_DEFAULT,
+ flags, start_type, start, stop_type, stop, &only_update);
- if (!gst_musepackdec_src_convert (pad, format, cur, &fmt, &offset)) {
+ if (flush) {
+ gst_pad_push_event (dec->srcpad, gst_event_new_flush_start ());
+ } else {
+ gst_pad_stop_task (dec->sinkpad);
+ }
- }
- if (!gst_musepackdec_src_convert (pad, GST_FORMAT_DEFAULT,
- musepackdec->len, &fmt, &len)) {
- res = FALSE;
- break;
- }
- if (!gst_musepackdec_src_convert (pad, GST_FORMAT_DEFAULT,
- musepackdec->pos, &fmt, &pos)) {
- res = FALSE;
- break;
- }
+ gst_pad_push_event (dec->sinkpad, gst_event_new_flush_start ());
+ GST_PAD_STREAM_LOCK (dec->sinkpad);
+ gst_pad_push_event (dec->sinkpad, gst_event_new_flush_stop ());
- /* offset from start */
- switch (cur_type) {
- case GST_SEEK_TYPE_SET:
- break;
- case GST_SEEK_TYPE_CUR:
- offset += pos;
- break;
- case GST_SEEK_TYPE_END:
- offset = len - offset;
- break;
- default:
- res = FALSE;
- goto done;
- }
+ GST_OBJECT_LOCK (dec);
- /* only valid seeks */
- if (offset >= len || offset < 0) {
- res = FALSE;
- break;
- }
+#if 0
+ if (only_update) {
+ dec->segment = segment;
+ gst_musepackdec_send_newsegment (dec, TRUE);
+ goto done;
+ }
+#endif
+
+ GST_DEBUG_OBJECT (dec, "segment: [%" G_GINT64_FORMAT "-%" G_GINT64_FORMAT
+ "] = [%" GST_TIME_FORMAT "-%" GST_TIME_FORMAT "]",
+ segment.start, segment.stop,
+ GST_TIME_ARGS (segment.start * GST_SECOND / dec->rate),
+ GST_TIME_ARGS (segment.stop * GST_SECOND / dec->rate));
+
+ GST_DEBUG_OBJECT (dec, "performing seek to sample %" G_GINT64_FORMAT,
+ segment.start);
+
+ if (flush) {
+ gst_pad_push_event (dec->srcpad, gst_event_new_flush_stop ());
+ }
+
+ if (segment.start < 0 || segment.start >= segment.duration) {
+ GST_WARNING_OBJECT (dec, "seek out of bounds");
+ GST_PAD_STREAM_UNLOCK (dec->sinkpad);
+ goto failed;
+ }
- /* store */
- musepackdec->seek_pending = TRUE;
- musepackdec->flush_pending = flags & GST_SEEK_FLAG_FLUSH;
- musepackdec->seek_time = offset;
- res = TRUE;
+ seek_ok = mpc_decoder_seek_sample (dec->d, segment.start);
+ if (!seek_ok) {
+ GST_PAD_STREAM_UNLOCK (dec->sinkpad);
+ goto failed;
+ }
+
+ /* FIXME: support segment seeks
+ if ((seek_flags & GST_SEEK_FLAG_SEGMENT) != 0) {
+ GST_DEBUG_OBJECT (dec, "posting SEGMENT_START message");
+ GST_OBJECT_UNLOCK (dec);
+ gst_element_post_message (GST_ELEMENT (dec),
+ gst_message_new_segment_start (GST_OBJECT (dec),
+ GST_FORMAT_DEFAULT, dec->segment.start));
+ GST_OBJECT_LOCK (dec);
+ }
+ */
+
+ gst_segment_set_last_stop (&segment, GST_FORMAT_DEFAULT, segment.start);
+ dec->segment = segment;
+ gst_musepackdec_send_newsegment (dec, FALSE);
+
+ GST_DEBUG_OBJECT (dec, "seek successful");
+
+#if 0
+done:
+#endif
+
+ GST_PAD_STREAM_UNLOCK (dec->sinkpad);
+
+ gst_pad_start_task (dec->sinkpad,
+ (GstTaskFunction) gst_musepackdec_loop, dec->sinkpad);
+
+ GST_OBJECT_UNLOCK (dec);
+ return TRUE;
+
+failed:
+ {
+ GST_WARNING_OBJECT (dec, "seek failed");
+ GST_OBJECT_UNLOCK (dec);
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_musepackdec_src_event (GstPad * pad, GstEvent * event)
+{
+ GstMusepackDec *dec;
+ gboolean res;
+
+ dec = GST_MUSEPACK_DEC (gst_pad_get_parent (pad));
+
+ GST_DEBUG_OBJECT (dec, "handling %s event", GST_EVENT_TYPE_NAME (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEEK:
+ res = gst_musepackdec_handle_seek_event (dec, event);
break;
- }
default:
res = gst_pad_event_default (pad, event);
- gst_object_unref (musepackdec);
- return res;
break;
}
-done:
- gst_event_unref (event);
- gst_object_unref (musepackdec);
+ gst_object_unref (dec);
return res;
}
@@ -313,6 +352,8 @@ gst_musepackdec_src_query (GstPad * pad, GstQuery * query)
gint64 value, dest_value;
gboolean res = TRUE;
+ GST_OBJECT_LOCK (musepackdec);
+
if (!musepackdec->init) {
res = FALSE;
goto done;
@@ -321,16 +362,16 @@ gst_musepackdec_src_query (GstPad * pad, GstQuery * query)
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_POSITION:
gst_query_parse_position (query, &dest_format, NULL);
- if (!gst_musepackdec_src_convert (pad, format, musepackdec->pos,
- &dest_format, &dest_value)) {
+ if (!gst_musepackdec_src_convert (pad, format,
+ musepackdec->segment.last_stop, &dest_format, &dest_value)) {
res = FALSE;
}
gst_query_set_position (query, dest_format, dest_value);
break;
case GST_QUERY_DURATION:
gst_query_parse_duration (query, &dest_format, NULL);
- if (!gst_musepackdec_src_convert (pad, format, musepackdec->len,
- &dest_format, &dest_value)) {
+ if (!gst_musepackdec_src_convert (pad, format,
+ musepackdec->segment.duration, &dest_format, &dest_value)) {
res = FALSE;
break;
}
@@ -346,16 +387,17 @@ gst_musepackdec_src_query (GstPad * pad, GstQuery * query)
gst_query_set_convert (query, format, value, dest_format, dest_value);
break;
default:
- res = FALSE;
+ res = gst_pad_query_default (pad, query);
break;
}
done:
+ GST_OBJECT_UNLOCK (musepackdec);
gst_object_unref (musepackdec);
return res;
}
-gboolean
+static gboolean
gst_musepackdec_src_convert (GstPad * pad, GstFormat src_format,
gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
{
@@ -363,6 +405,7 @@ gst_musepackdec_src_convert (GstPad * pad, GstFormat src_format,
gboolean res = TRUE;
if (!musepackdec->init) {
+ GST_DEBUG_OBJECT (musepackdec, "conversion failed: not initialiased yet");
gst_object_unref (musepackdec);
return FALSE;
}
@@ -371,7 +414,8 @@ gst_musepackdec_src_convert (GstPad * pad, GstFormat src_format,
case GST_FORMAT_DEFAULT:
switch (*dest_format) {
case GST_FORMAT_TIME:
- *dest_value = src_value * GST_SECOND / musepackdec->rate;
+ *dest_value = gst_util_uint64_scale_int (src_value,
+ GST_SECOND, musepackdec->rate);
break;
case GST_FORMAT_BYTES:
*dest_value = src_value * musepackdec->bps;
@@ -385,11 +429,12 @@ gst_musepackdec_src_convert (GstPad * pad, GstFormat src_format,
case GST_FORMAT_TIME:
switch (*dest_format) {
case GST_FORMAT_DEFAULT:
- *dest_value = src_value * musepackdec->rate / GST_SECOND;
+ *dest_value = gst_util_uint64_scale_int (src_value,
+ musepackdec->rate, GST_SECOND);
break;
case GST_FORMAT_BYTES:
- *dest_value = src_value * musepackdec->rate *
- musepackdec->bps / GST_SECOND;
+ *dest_value = gst_util_uint64_scale_int (src_value,
+ musepackdec->rate * musepackdec->bps, GST_SECOND);
break;
default:
res = FALSE;
@@ -403,8 +448,8 @@ gst_musepackdec_src_convert (GstPad * pad, GstFormat src_format,
*dest_value = src_value / musepackdec->bps;
break;
case GST_FORMAT_TIME:
- *dest_value = src_value * GST_SECOND /
- (musepackdec->bps * musepackdec->rate);
+ *dest_value = gst_util_uint64_scale_int (src_value,
+ GST_SECOND, musepackdec->bps * musepackdec->rate);
break;
default:
res = FALSE;
@@ -418,13 +463,14 @@ gst_musepackdec_src_convert (GstPad * pad, GstFormat src_format,
}
gst_object_unref (musepackdec);
- return TRUE;
+ return res;
}
static gboolean
gst_musepack_stream_init (GstMusepackDec * musepackdec)
{
mpc_streaminfo i;
+ GstTagList *tags;
GstCaps *caps;
/* set up reading */
@@ -459,9 +505,46 @@ gst_musepack_stream_init (GstMusepackDec * musepackdec)
musepackdec->bps = 4 * i.channels;;
musepackdec->rate = i.sample_freq;
- musepackdec->pos = 0;
- musepackdec->len = mpc_streaminfo_get_length_samples (&i);
- musepackdec->init = TRUE;
+
+ gst_segment_set_last_stop (&musepackdec->segment, GST_FORMAT_DEFAULT, 0);
+ gst_segment_set_duration (&musepackdec->segment, GST_FORMAT_DEFAULT,
+ mpc_streaminfo_get_length_samples (&i));
+
+ /* send basic tags */
+ tags = gst_tag_list_new ();
+ gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
+ GST_TAG_AUDIO_CODEC, "Musepack", NULL);
+
+ if (i.encoder[0] != '\0' && i.encoder_version > 0) {
+ gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
+ GST_TAG_ENCODER, i.encoder,
+ GST_TAG_ENCODER_VERSION, i.encoder_version, NULL);
+ }
+
+ if (i.bitrate > 0) {
+ gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
+ GST_TAG_BITRATE, i.bitrate, NULL);
+ } else if (i.average_bitrate > 0.0) {
+ gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
+ GST_TAG_BITRATE, (guint) i.average_bitrate, NULL);
+ }
+
+ /* FIXME: are these values correct in the end? */
+ if (i.gain_title != 0 || i.gain_album != 0) {
+ gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
+ GST_TAG_TRACK_GAIN, (gdouble) i.gain_title / 100.0,
+ GST_TAG_ALBUM_GAIN, (gdouble) i.gain_album / 100.0, NULL);
+ }
+
+ /* FIXME: are these values correct in the end? */
+ if (i.peak_title != 0 && i.peak_album != 0) {
+ gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
+ GST_TAG_TRACK_PEAK, (gdouble) i.peak_title,
+ GST_TAG_ALBUM_PEAK, (gdouble) i.peak_album, NULL);
+ }
+
+ GST_LOG_OBJECT (musepackdec, "Posting tags: %" GST_PTR_FORMAT, tags);
+ gst_element_found_tags (GST_ELEMENT (musepackdec), tags);
return TRUE;
}
@@ -484,7 +567,6 @@ gst_musepackdec_sink_activate_pull (GstPad * sinkpad, gboolean active)
gboolean result;
if (active) {
-
result = gst_pad_start_task (sinkpad,
(GstTaskFunction) gst_musepackdec_loop, sinkpad);
} else {
@@ -497,72 +579,67 @@ gst_musepackdec_sink_activate_pull (GstPad * sinkpad, gboolean active)
static void
gst_musepackdec_loop (GstPad * sinkpad)
{
- GstMusepackDec *musepackdec = GST_MUSEPACK_DEC (GST_PAD_PARENT (sinkpad));
+ GstMusepackDec *musepackdec;
+ GstFlowReturn flow;
GstBuffer *out;
- GstFormat fmt;
- gint ret;
guint32 update_acc, update_bits;
+ gint num_samples;
+
+ musepackdec = GST_MUSEPACK_DEC (GST_PAD_PARENT (sinkpad));
if (!musepackdec->init) {
if (!gst_musepack_stream_init (musepackdec))
- return;
- gst_pad_push_event (musepackdec->srcpad,
- gst_event_new_new_segment (FALSE, 1.0,
- GST_FORMAT_TIME, musepackdec->pos, GST_CLOCK_TIME_NONE, 0));
- }
-
- if (musepackdec->seek_pending) {
- gdouble seek_time = (gdouble) musepackdec->seek_time / GST_SECOND;
+ goto pause_task;
- musepackdec->seek_pending = FALSE;
- if (mpc_decoder_seek_seconds (musepackdec->d, seek_time)) {
- if (musepackdec->flush_pending) {
- musepackdec->flush_pending = FALSE;
- gst_pad_push_event (musepackdec->srcpad, gst_event_new_flush_start ());
- }
- gst_pad_push_event (musepackdec->srcpad,
- gst_event_new_new_segment (FALSE, 1.0,
- GST_FORMAT_TIME, musepackdec->seek_time, GST_CLOCK_TIME_NONE, 0));
- fmt = GST_FORMAT_DEFAULT;
- gst_musepackdec_src_convert (musepackdec->srcpad,
- GST_FORMAT_TIME, musepackdec->seek_time,
- &fmt, (gint64 *) & musepackdec->pos);
- }
+ musepackdec->init = TRUE;
+ gst_musepackdec_send_newsegment (musepackdec, FALSE);
}
out = gst_buffer_new_and_alloc (MPC_DECODER_BUFFER_LENGTH * 4);
- ret = mpc_decoder_decode (musepackdec->d,
+
+ num_samples = mpc_decoder_decode (musepackdec->d,
(MPC_SAMPLE_FORMAT *) GST_BUFFER_DATA (out), &update_acc, &update_bits);
- if (ret <= 0 || musepackdec->eos) {
- if (ret < 0) {
- GST_ERROR_OBJECT (musepackdec, "Failed to decode sample");
- } else if (!musepackdec->eos) {
- musepackdec->eos = TRUE;
- gst_pad_push_event (musepackdec->sinkpad, gst_event_new_eos ());
- }
- gst_buffer_unref (out);
- return;
+
+ if (num_samples < 0) {
+ GST_ERROR_OBJECT (musepackdec, "Failed to decode sample");
+ GST_ELEMENT_ERROR (musepackdec, STREAM, DECODE, (NULL), (NULL));
+ goto pause_task;
+ } else if (num_samples == 0) {
+ GST_DEBUG_OBJECT (musepackdec, "EOS");
+ gst_pad_push_event (musepackdec->srcpad, gst_event_new_eos ());
+ goto pause_task;
}
- GST_BUFFER_SIZE (out) = ret * musepackdec->bps;
- fmt = GST_FORMAT_TIME;
+ GST_BUFFER_SIZE (out) = num_samples * musepackdec->bps;
- gint64 value;
+ GST_BUFFER_OFFSET (out) = musepackdec->segment.last_stop;
+ GST_BUFFER_TIMESTAMP (out) =
+ gst_util_uint64_scale_int (musepackdec->segment.last_stop,
+ GST_SECOND, musepackdec->rate);
+ GST_BUFFER_DURATION (out) =
+ gst_util_uint64_scale_int (num_samples, GST_SECOND, musepackdec->rate);
- gst_musepackdec_src_convert (musepackdec->srcpad,
- GST_FORMAT_BYTES, GST_BUFFER_SIZE (out), &fmt, &value);
- GST_BUFFER_DURATION (out) = value;
+ gst_buffer_set_caps (out, GST_PAD_CAPS (musepackdec->srcpad));
- gst_musepackdec_src_convert (musepackdec->srcpad,
- GST_FORMAT_DEFAULT, musepackdec->pos, &fmt, &value);
- GST_BUFFER_TIMESTAMP (out) = value;
+ musepackdec->segment.last_stop += num_samples;
- GST_DEBUG ("Pushing buffer, timestamp %" GST_TIME_FORMAT,
+ GST_LOG_OBJECT (musepackdec, "Pushing buffer, timestamp %" GST_TIME_FORMAT,
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out)));
- musepackdec->pos += GST_BUFFER_SIZE (out) / musepackdec->bps;
- gst_buffer_set_caps (out, GST_PAD_CAPS (musepackdec->srcpad));
- gst_pad_push (musepackdec->srcpad, out);
+ flow = gst_pad_push (musepackdec->srcpad, out);
+ if (flow != GST_FLOW_OK && flow != GST_FLOW_NOT_LINKED) {
+ GST_DEBUG_OBJECT (musepackdec, "Flow: %s", gst_flow_get_name (flow));
+ goto pause_task;
+ }
+
+ return;
+
+pause_task:
+ {
+ GST_DEBUG_OBJECT (musepackdec, "Pausing task");
+ gst_pad_pause_task (sinkpad);
+ return;
+ }
}
static GstStateChangeReturn
@@ -571,14 +648,23 @@ gst_musepackdec_change_state (GstElement * element, GstStateChange transition)
GstMusepackDec *musepackdec = GST_MUSEPACK_DEC (element);
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_segment_init (&musepackdec->segment, GST_FORMAT_DEFAULT);
+ gst_segment_set_last_stop (&musepackdec->segment, GST_FORMAT_DEFAULT, 0);
+ break;
+ default:
+ break;
+ }
+
if (GST_ELEMENT_CLASS (parent_class)->change_state)
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
- musepackdec->seek_pending = FALSE;
+ gst_segment_init (&musepackdec->segment, GST_FORMAT_UNDEFINED);
musepackdec->init = FALSE;
+ musepackdec->offset = 0;
break;
default:
break;
diff --git a/ext/musepack/gstmusepackdec.h b/ext/musepack/gstmusepackdec.h
index 3743519cd..52105b8a0 100644
--- a/ext/musepack/gstmusepackdec.h
+++ b/ext/musepack/gstmusepackdec.h
@@ -21,9 +21,7 @@
#define __GST_MUSEPACK_DEC_H__
#include <gst/gst.h>
-//#include <gst/bytestream/bytestream.h>
#include <mpcdec/mpcdec.h>
-//#include "gstmusepackreader.h"
G_BEGIN_DECLS
@@ -37,7 +35,7 @@ G_BEGIN_DECLS
GstMusepackDecClass))
#define GST_IS_MUSEPACK_DEC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MUSEPACK_DEC))
-#define GST_IS_MUSEPACK_DEC_CLASS(obj) \
+#define GST_IS_MUSEPACK_DEC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MUSEPACK_DEC))
typedef struct _GstMusepackDec {
@@ -45,7 +43,6 @@ typedef struct _GstMusepackDec {
/* pads */
GstPad *srcpad, *sinkpad;
- // GstByteStream *bs;
guint64 offset;
/* MUSEPACK_DEC object */
@@ -53,15 +50,12 @@ typedef struct _GstMusepackDec {
mpc_reader *r;
gboolean init;
- /* bytes-per-sample */
- int bps, rate;
+ /* bytes per sample and sample rate */
+ guint bps;
+ guint rate;
- /* position and length, in samples */
- guint64 pos, len;
-
- /* seeks */
- gdouble flush_pending, seek_pending, eos;
- guint64 seek_time;
+ /* currently configured segment, in samples (DEFAULT format) */
+ GstSegment segment;
} GstMusepackDec;
typedef struct _GstMusepackDecClass {
@@ -70,10 +64,6 @@ typedef struct _GstMusepackDecClass {
GType gst_musepackdec_get_type (void);
-extern gboolean gst_musepackdec_src_convert (GstPad * pad,
- GstFormat src_format,
- gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
-
G_END_DECLS
#endif /* __GST_MUSEPACK_DEC_H__ */
diff --git a/ext/musepack/gstmusepackreader.c b/ext/musepack/gstmusepackreader.c
index 6595c637a..a801f7cc3 100644
--- a/ext/musepack/gstmusepackreader.c
+++ b/ext/musepack/gstmusepackreader.c
@@ -26,72 +26,48 @@
#include "gstmusepackreader.h"
+GST_DEBUG_CATEGORY_EXTERN (musepackdec_debug);
+#define GST_CAT_DEFAULT musepackdec_debug
+
+static mpc_int32_t gst_musepack_reader_peek (void *this, void *ptr,
+ mpc_int32_t size);
+static mpc_int32_t gst_musepack_reader_read (void *this, void *ptr,
+ mpc_int32_t size);
+static mpc_bool_t gst_musepack_reader_seek (void *this, mpc_int32_t offset);
+static mpc_int32_t gst_musepack_reader_tell (void *this);
+static mpc_int32_t gst_musepack_reader_get_size (void *this);
+static mpc_bool_t gst_musepack_reader_canseek (void *this);
+
static mpc_int32_t
gst_musepack_reader_peek (void *this, void *ptr, mpc_int32_t size)
{
GstMusepackDec *musepackdec = GST_MUSEPACK_DEC (this);
+ GstFlowReturn flow_ret;
GstBuffer *buf = NULL;
- gint read;
+ guint read;
- if (musepackdec->eos) {
- return 0;
- }
+ g_return_val_if_fail (size > 0, 0);
- do {
- if (GST_FLOW_OK != gst_pad_pull_range (musepackdec->sinkpad,
- musepackdec->offset, size, &buf)) {
- return 0;
- }
+ /* GST_LOG_OBJECT (musepackdec, "size=%d", size); */
- read = GST_BUFFER_SIZE (buf);
+ flow_ret = gst_pad_pull_range (musepackdec->sinkpad, musepackdec->offset,
+ size, &buf);
- if (musepackdec->eos ||
- musepackdec->flush_pending || musepackdec->seek_pending) {
- break;
- }
+ if (flow_ret != GST_FLOW_OK) {
+ GST_DEBUG_OBJECT (musepackdec, "Flow: %s", gst_flow_get_name (flow_ret));
+ return 0;
+ }
+ read = MIN (GST_BUFFER_SIZE (buf), size);
- /* FIX ME: do i have to handle those event in sink_event? */
- /* we pipeline doesnt stop after receive EOS */
- /*
-
- if (read != size) {
- GstEvent *event;
- guint32 remaining;
-
- gst_bytestream_get_status (bs, &remaining, &event);
- if (!event) {
- GST_ELEMENT_ERROR (gst_pad_get_parent (bs->pad),
- RESOURCE, READ, (NULL), (NULL));
- goto done;
- }
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_INTERRUPT:
- gst_event_unref (event);
- goto done;
- case GST_EVENT_EOS:
- gst_event_unref (event);
- goto done;
- case GST_EVENT_FLUSH:
- gst_event_unref (event);
- break;
- case GST_EVENT_DISCONTINUOUS:
- gst_event_unref (event);
- break;
- default:
- gst_pad_event_default (bs->pad, event);
- break;
- }
- }
- */
- } while (read != size);
-
- if (read != 0) {
- memcpy (ptr, GST_BUFFER_DATA (buf), read);
+ if (read < size) {
+ GST_WARNING_OBJECT (musepackdec, "Short read: got only %u bytes of %u "
+ "bytes requested", read, size);
+ /* GST_ELEMENT_ERROR (musepackdec, RESOURCE, READ, (NULL), (NULL)); */
}
- gst_buffer_unref (buf);
+ memcpy (ptr, GST_BUFFER_DATA (buf), read);
+ gst_buffer_unref (buf);
return read;
}
@@ -113,83 +89,44 @@ static mpc_bool_t
gst_musepack_reader_seek (void *this, mpc_int32_t offset)
{
GstMusepackDec *musepackdec = GST_MUSEPACK_DEC (this);
- guint8 dummy;
-
- /* hacky hack - if we're after typefind, we'll fail because
- * typefind is still typefinding (heh :) ). So read first. */
- gst_musepack_reader_peek (this, &dummy, 1);
+ mpc_int32_t length;
- /* seek */
- musepackdec->offset = offset;
-
- /* get discont */
- if (gst_musepack_reader_peek (this, &dummy, 1) != 1)
+ length = gst_musepack_reader_get_size (this);
+ if (length > 0 && offset >= 0 && offset < length) {
+ musepackdec->offset = offset;
+ GST_LOG_OBJECT (musepackdec, "Seek'ed to byte offset %d", (gint) offset);
+ return TRUE;
+ } else {
+ GST_DEBUG_OBJECT (musepackdec, "Cannot seek to offset %d", (gint) offset);
return FALSE;
-
- return TRUE;
+ }
}
static mpc_int32_t
gst_musepack_reader_tell (void *this)
{
GstMusepackDec *musepackdec = GST_MUSEPACK_DEC (this);
- GstQuery *query;
- gint64 position;
- GstFormat format = GST_FORMAT_BYTES;
- query = gst_query_new_position (GST_FORMAT_BYTES);
- if (gst_pad_query (musepackdec->sinkpad, query)) {
-
- gst_query_parse_position (query, &format, &position);
-
- if (format != GST_FORMAT_BYTES) {
- GstFormat dest_format = GST_FORMAT_BYTES;
-
- if (!gst_musepackdec_src_convert (musepackdec->srcpad,
- format, position, &dest_format, &position)) {
- position = -1;
- }
-
- }
-
- } else {
- position = -1;
- }
- gst_query_unref (query);
-
- return position;
+ return musepackdec->offset;
}
static mpc_int32_t
gst_musepack_reader_get_size (void *this)
{
- GstMusepackDec *musepackdec = GST_MUSEPACK_DEC (this);
- GstQuery *query;
- gint64 duration;
+ GstMusepackDec *dec = GST_MUSEPACK_DEC (this);
GstFormat format = GST_FORMAT_BYTES;
+ gint64 length = -1;
+ GstPad *peer;
- query = gst_query_new_duration (GST_FORMAT_BYTES);
- if (gst_pad_query (musepackdec->sinkpad, query)) {
-
- gst_query_parse_duration (query, &format, &duration);
-
- if (format != GST_FORMAT_BYTES) {
- GstFormat dest_format = GST_FORMAT_BYTES;
-
- if (!gst_musepackdec_src_convert (musepackdec->srcpad,
- format, duration, &dest_format, &duration)) {
- duration = -1;
- }
-
+ peer = gst_pad_get_peer (dec->sinkpad);
+ if (peer) {
+ if (!gst_pad_query_duration (peer, &format, &length) || length <= 0) {
+ length = -1;
}
-
- } else {
- duration = -1;
+ gst_object_unref (peer);
}
- gst_query_unref (query);
-
- return duration;
+ return (mpc_int32_t) length;
}
static mpc_bool_t
diff --git a/ext/musepack/gstmusepackreader.h b/ext/musepack/gstmusepackreader.h
index d5a477cb0..77a6bb062 100644
--- a/ext/musepack/gstmusepackreader.h
+++ b/ext/musepack/gstmusepackreader.h
@@ -21,7 +21,6 @@
#define __GST_MUSEPACK_READER_H__
#include <mpcdec/mpcdec.h>
-//#include <gst/bytestream/bytestream.h>
#include "gstmusepackdec.h"
void gst_musepack_init_reader (mpc_reader * r, GstMusepackDec * musepackdec);