diff options
Diffstat (limited to 'ext')
-rw-r--r-- | ext/musepack/gstmusepackdec.c | 486 | ||||
-rw-r--r-- | ext/musepack/gstmusepackdec.h | 22 | ||||
-rw-r--r-- | ext/musepack/gstmusepackreader.c | 159 | ||||
-rw-r--r-- | ext/musepack/gstmusepackreader.h | 1 |
4 files changed, 340 insertions, 328 deletions
diff --git a/ext/musepack/gstmusepackdec.c b/ext/musepack/gstmusepackdec.c index 2216b591..9a32c1c8 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 3743519c..52105b8a 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 6595c637..a801f7cc 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 d5a477cb..77a6bb06 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); |