From 5df1c827fbca23bdd07e6c6c0cc0f03a2dc29b26 Mon Sep 17 00:00:00 2001 From: Edgard Lima Date: Tue, 8 Nov 2005 13:55:13 +0000 Subject: Ported to 0.9. Some issues to be solved yet: 1- set correct timestamps 2- seg fault when eos 3- seek is now disabled Original commit message from CVS: Ported to 0.9. Some issues to be solved yet: 1- set correct timestamps 2- seg fault when eos 3- seek is now disabled --- ext/ivorbis/vorbis.c | 3 - ext/ivorbis/vorbisfile.c | 515 ++++++++++++++++++++++++++++++----------------- 2 files changed, 335 insertions(+), 183 deletions(-) (limited to 'ext/ivorbis') diff --git a/ext/ivorbis/vorbis.c b/ext/ivorbis/vorbis.c index 3394a77a..592d9d2a 100644 --- a/ext/ivorbis/vorbis.c +++ b/ext/ivorbis/vorbis.c @@ -30,9 +30,6 @@ extern GType ivorbisfile_get_type (void); static gboolean plugin_init (GstPlugin * plugin) { - if (!gst_library_load ("gstbytestream")) - return FALSE; - if (!gst_element_register (plugin, "tremor", GST_RANK_PRIMARY, ivorbisfile_get_type ())) return FALSE; diff --git a/ext/ivorbis/vorbisfile.c b/ext/ivorbis/vorbisfile.c index db2b601b..6ab26714 100644 --- a/ext/ivorbis/vorbisfile.c +++ b/ext/ivorbis/vorbisfile.c @@ -24,20 +24,20 @@ #include #include #include -#include +#include GST_DEBUG_CATEGORY_STATIC (ivorbisfile_debug); #define GST_CAT_DEFAULT ivorbisfile_debug -#define GST_TYPE_IVORBISFILE \ +#define GST_TYPE_IVORBISFILE \ (ivorbisfile_get_type()) -#define GST_IVORBISFILE(obj) \ +#define GST_IVORBISFILE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_IVORBISFILE,Ivorbisfile)) -#define GST_IVORBISFILE_CLASS(klass) \ +#define GST_IVORBISFILE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_IVORBISFILE,IvorbisfileClass)) -#define GST_IS_IVORBISFILE(obj) \ +#define GST_IS_IVORBISFILE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_IVORBISFILE)) -#define GST_IS_IVORBISFILE_CLASS(obj) \ +#define GST_IS_IVORBISFILE_CLASS(obj) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_IVORBISFILE)) typedef struct _Ivorbisfile Ivorbisfile; @@ -48,7 +48,8 @@ struct _Ivorbisfile GstElement element; GstPad *sinkpad, *srcpad; - GstByteStream *bs; + GstAdapter *adapter; + guint64 adapterOffset; OggVorbis_File vf; gint current_link; @@ -65,6 +66,10 @@ struct _Ivorbisfile guint64 total_bytes; guint64 offset; + gint rate; + gint channels; + gint width; + GstCaps *metadata; GstCaps *streaminfo; }; @@ -109,30 +114,37 @@ static void gst_ivorbisfile_init (Ivorbisfile * ivorbisfile); static GstStateChangeReturn gst_ivorbisfile_change_state (GstElement * element, GstStateChange transition); -static const GstFormat *gst_ivorbisfile_get_formats (GstPad * pad); static gboolean gst_ivorbisfile_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value, GstFormat * dest_format, gint64 * dest_value); static gboolean gst_ivorbisfile_sink_convert (GstPad * pad, GstFormat src_format, gint64 src_value, GstFormat * dest_format, gint64 * dest_value); -static const GstQueryType *gst_ivorbisfile_get_query_types (GstPad * pad); +static const GstQueryType *gst_ivorbisfile_get_src_query_types (GstPad * pad); + +static gboolean gst_ivorbisfile_src_query (GstPad * pad, GstQuery * query); -static gboolean gst_ivorbisfile_src_query (GstPad * pad, - GstQueryType type, GstFormat * format, gint64 * value); -static const GstEventMask *gst_ivorbisfile_get_event_masks (GstPad * pad); static gboolean gst_ivorbisfile_src_event (GstPad * pad, GstEvent * event); +static gboolean gst_ivorbisfile_sink_event (GstPad * pad, GstEvent * event); + +static const GstQueryType *gst_ivorbisfile_get_sink_query_types (GstPad * pad); + +static gboolean gst_ivorbisfile_sink_query (GstPad * pad, GstQuery * query); + static void gst_ivorbisfile_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static void gst_ivorbisfile_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_ivorbisfile_loop (GstElement * element); +static gboolean gst_ivorbisfile_sink_activate (GstPad * sinkpad); -static GstElementClass *parent_class = NULL; +static gboolean +gst_ivorbisfile_sink_activate_pull (GstPad * sinkpad, gboolean active); + +static void gst_ivorbisfile_loop (GstPad * pad); -//static guint gst_ivorbisfile_signals[LAST_SIGNAL] = { 0 }; +static GstElementClass *parent_class = NULL; static GstFormat logical_stream_format; @@ -230,6 +242,9 @@ gst_ivorbisfile_class_init (IvorbisfileClass * klass) parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + gobject_class->get_property = gst_ivorbisfile_get_property; + gobject_class->set_property = gst_ivorbisfile_set_property; + g_object_class_install_property (gobject_class, ARG_METADATA, g_param_spec_boxed ("metadata", "Metadata", "(logical) Stream metadata", GST_TYPE_CAPS, G_PARAM_READABLE)); @@ -237,8 +252,6 @@ gst_ivorbisfile_class_init (IvorbisfileClass * klass) g_param_spec_boxed ("streaminfo", "stream", "(logical) Stream information", GST_TYPE_CAPS, G_PARAM_READABLE)); - gobject_class->get_property = gst_ivorbisfile_get_property; - gobject_class->set_property = gst_ivorbisfile_set_property; gstelement_class->change_state = gst_ivorbisfile_change_state; } @@ -249,26 +262,27 @@ gst_ivorbisfile_init (Ivorbisfile * ivorbisfile) ivorbisfile->sinkpad = gst_pad_new_from_template (gst_vorbisdec_sink_template, "sink"); gst_element_add_pad (GST_ELEMENT (ivorbisfile), ivorbisfile->sinkpad); - gst_pad_set_formats_function (ivorbisfile->sinkpad, - gst_ivorbisfile_get_formats); - gst_pad_set_convert_function (ivorbisfile->sinkpad, - gst_ivorbisfile_sink_convert); - gst_element_set_loop_function (GST_ELEMENT (ivorbisfile), - gst_ivorbisfile_loop); + gst_pad_set_query_type_function (ivorbisfile->sinkpad, + gst_ivorbisfile_get_sink_query_types); + gst_pad_set_query_function (ivorbisfile->sinkpad, gst_ivorbisfile_sink_query); + + gst_pad_set_activate_function (ivorbisfile->sinkpad, + gst_ivorbisfile_sink_activate); + gst_pad_set_activatepull_function (ivorbisfile->sinkpad, + gst_ivorbisfile_sink_activate_pull); + + gst_pad_set_event_function (ivorbisfile->sinkpad, gst_ivorbisfile_sink_event); + ivorbisfile->srcpad = gst_pad_new_from_template (gst_vorbisdec_src_template, "src"); gst_element_add_pad (GST_ELEMENT (ivorbisfile), ivorbisfile->srcpad); - gst_pad_set_formats_function (ivorbisfile->srcpad, - gst_ivorbisfile_get_formats); + gst_pad_set_query_type_function (ivorbisfile->srcpad, - gst_ivorbisfile_get_query_types); + gst_ivorbisfile_get_src_query_types); gst_pad_set_query_function (ivorbisfile->srcpad, gst_ivorbisfile_src_query); - gst_pad_set_event_mask_function (ivorbisfile->srcpad, - gst_ivorbisfile_get_event_masks); + gst_pad_set_event_function (ivorbisfile->srcpad, gst_ivorbisfile_src_event); - gst_pad_set_convert_function (ivorbisfile->srcpad, - gst_ivorbisfile_src_convert); ivorbisfile->total_bytes = 0; ivorbisfile->offset = 0; @@ -277,6 +291,11 @@ gst_ivorbisfile_init (Ivorbisfile * ivorbisfile) ivorbisfile->metadata = NULL; ivorbisfile->streaminfo = NULL; ivorbisfile->current_link = -1; + + ivorbisfile->rate = -1; + ivorbisfile->channels = -1; + ivorbisfile->width = -1; + } /* the next four functions are the ov callbacks we provide to ivorbisfile @@ -285,15 +304,15 @@ gst_ivorbisfile_init (Ivorbisfile * ivorbisfile) static size_t gst_ivorbisfile_read (void *ptr, size_t size, size_t nmemb, void *datasource) { - guint32 got_bytes = 0; - guint8 *data; size_t read_size = size * nmemb; - + GstBuffer *buf = NULL; Ivorbisfile *ivorbisfile = GST_IVORBISFILE (datasource); + size_t ret; GST_DEBUG ("read %d", read_size); /* make sure we don't go to EOS */ + if (!ivorbisfile->may_eos && ivorbisfile->total_bytes && ivorbisfile->offset + read_size > ivorbisfile->total_bytes) { read_size = ivorbisfile->total_bytes - ivorbisfile->offset; @@ -302,50 +321,25 @@ gst_ivorbisfile_read (void *ptr, size_t size, size_t nmemb, void *datasource) if (read_size == 0 || ivorbisfile->eos) return 0; - while (got_bytes == 0) { - got_bytes = gst_bytestream_peek_bytes (ivorbisfile->bs, &data, read_size); - if (got_bytes < read_size) { - GstEvent *event; - guint32 avail; - - gst_bytestream_get_status (ivorbisfile->bs, &avail, &event); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_EOS: - GST_DEBUG ("eos"); - ivorbisfile->eos = TRUE; - if (avail == 0) { - gst_event_unref (event); - return 0; - } - break; - case GST_EVENT_DISCONTINUOUS: - GST_DEBUG ("discont"); - ivorbisfile->need_discont = TRUE; - default: - break; - } - gst_event_unref (event); - if (avail > 0) - got_bytes = gst_bytestream_peek_bytes (ivorbisfile->bs, &data, avail); - else - got_bytes = 0; - } + if (GST_FLOW_OK != gst_pad_pull_range (ivorbisfile->sinkpad, + ivorbisfile->offset, read_size, &buf)) { + return 0; } - memcpy (ptr, data, got_bytes); - gst_bytestream_flush_fast (ivorbisfile->bs, got_bytes); + memcpy (ptr, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); - ivorbisfile->offset += got_bytes; + ivorbisfile->offset += GST_BUFFER_SIZE (buf); - return got_bytes / size; + ret = GST_BUFFER_SIZE (buf) / size; + gst_buffer_unref (buf); + + return ret; } static int gst_ivorbisfile_seek (void *datasource, int64_t offset, int whence) { Ivorbisfile *ivorbisfile = GST_IVORBISFILE (datasource); - GstSeekType method; guint64 pending_offset = ivorbisfile->offset; gboolean need_total = FALSE; @@ -357,24 +351,22 @@ gst_ivorbisfile_seek (void *datasource, int64_t offset, int whence) GST_DEBUG ("seek %" G_GINT64_FORMAT " %d", offset, whence); if (whence == SEEK_SET) { - method = GST_SEEK_METHOD_SET; pending_offset = offset; + ivorbisfile->adapterOffset = offset; } else if (whence == SEEK_CUR) { - method = GST_SEEK_METHOD_CUR; pending_offset += offset; + ivorbisfile->adapterOffset += offset; } else if (whence == SEEK_END) { - method = GST_SEEK_METHOD_END; need_total = TRUE; pending_offset = ivorbisfile->total_bytes - offset; + ivorbisfile->adapterOffset = ivorbisfile->total_bytes - offset; } else return -1; - if (!gst_bytestream_seek (ivorbisfile->bs, offset, method)) - return -1; ivorbisfile->offset = pending_offset; if (need_total) - ivorbisfile->total_bytes = gst_bytestream_tell (ivorbisfile->bs) + offset; + ivorbisfile->total_bytes = ivorbisfile->adapterOffset + offset; return 0; } @@ -392,7 +384,7 @@ gst_ivorbisfile_tell (void *datasource) Ivorbisfile *ivorbisfile = GST_IVORBISFILE (datasource); long result; - result = gst_bytestream_tell (ivorbisfile->bs); + result = ivorbisfile->adapterOffset; GST_DEBUG ("tell %ld", result); @@ -513,40 +505,89 @@ gst_ivorbisfile_new_link (Ivorbisfile * ivorbisfile, gint link) "depth", G_TYPE_INT, 16, "rate", G_TYPE_INT, vi->rate, "channels", G_TYPE_INT, vi->channels, NULL); - if (gst_pad_try_set_caps (ivorbisfile->srcpad, caps) <= 0) { + ivorbisfile->rate = vi->rate; + ivorbisfile->channels = vi->channels; + ivorbisfile->width = 16; + + if (gst_pad_set_caps (ivorbisfile->srcpad, caps) <= 0) { res = FALSE; } - gst_caps_free (caps); + gst_caps_unref (caps); return TRUE; } + +static gboolean +gst_ivorbisfile_sink_activate (GstPad * sinkpad) +{ + + Ivorbisfile *ivorbisfile; + + ivorbisfile = GST_IVORBISFILE (GST_PAD_PARENT (sinkpad)); + + if (gst_pad_check_pull_range (sinkpad)) { + /* FIX ME */ + /* ivorbisfile->vf.seekable = TRUE; */ + ivorbisfile->vf.seekable = FALSE; + return gst_pad_activate_pull (sinkpad, TRUE); + } + + ivorbisfile->vf.seekable = FALSE; + return FALSE; + + +} + + +static gboolean +gst_ivorbisfile_sink_activate_pull (GstPad * sinkpad, gboolean active) +{ + + gboolean result; + + if (active) { + /* if we have a scheduler we can start the task */ + result = gst_pad_start_task (sinkpad, + (GstTaskFunction) gst_ivorbisfile_loop, sinkpad); + } else { + result = gst_pad_stop_task (sinkpad); + } + + return result; +} + + + static void -gst_ivorbisfile_loop (GstElement * element) +gst_ivorbisfile_loop (GstPad * pad) { - Ivorbisfile *ivorbisfile = GST_IVORBISFILE (element); + Ivorbisfile *ivorbisfile = GST_IVORBISFILE (GST_PAD_PARENT (pad)); GstBuffer *outbuf; long ret; GstClockTime time; gint64 samples; gint link; + if (ivorbisfile->eos) + return; + /* this function needs to go first since you don't want to be messing * with an unset vf ;) */ if (ivorbisfile->restart) { + ivorbisfile->offset = 0; ivorbisfile->total_bytes = 0; ivorbisfile->may_eos = FALSE; - ivorbisfile->vf.seekable = gst_bytestream_seek (ivorbisfile->bs, 0, - GST_SEEK_METHOD_SET); + ivorbisfile->adapterOffset = 0; GST_DEBUG ("ivorbisfile: seekable: %s\n", ivorbisfile->vf.seekable ? "yes" : "no"); /* open our custom ivorbisfile data object with the callbacks we provide */ if (ov_open_callbacks (ivorbisfile, &ivorbisfile->vf, NULL, 0, ivorbisfile_ov_callbacks) < 0) { - GST_ELEMENT_ERROR (element, STREAM, DECODE, (NULL), (NULL)); + GST_ELEMENT_ERROR (ivorbisfile, STREAM, DECODE, (NULL), (NULL)); return; } ivorbisfile->need_discont = TRUE; @@ -615,24 +656,21 @@ gst_ivorbisfile_loop (GstElement * element) GST_BUFFER_DATA (outbuf) = g_malloc (4096); GST_BUFFER_SIZE (outbuf) = 4096; + ret = ov_read (&ivorbisfile->vf, + (char *) GST_BUFFER_DATA (outbuf), GST_BUFFER_SIZE (outbuf), &link); + /* get current time for discont and buffer timestamp */ time = (GstClockTime) (ov_time_tell (&ivorbisfile->vf) * GST_SECOND); - ret = ov_read (&ivorbisfile->vf, - GST_BUFFER_DATA (outbuf), GST_BUFFER_SIZE (outbuf), &link); - if (ret == 0) { GST_DEBUG ("eos"); /* send EOS event */ - /*ov_clear (&ivorbisfile->vf); */ + ivorbisfile->restart = TRUE; gst_buffer_unref (outbuf); /* if the pad is not usable, don't push it out */ - if (GST_PAD_IS_USABLE (ivorbisfile->srcpad)) { - gst_pad_push (ivorbisfile->srcpad, - GST_DATA (gst_event_new (GST_EVENT_EOS))); - } - gst_element_set_eos (element); + gst_pad_push_event (ivorbisfile->srcpad, gst_event_new_eos ()); + return; } else if (ret < 0) { g_warning ("ivorbisfile: decoding error"); @@ -640,24 +678,30 @@ gst_ivorbisfile_loop (GstElement * element) return; } else { if (ivorbisfile->need_discont) { - GstEvent *discont; + GstEvent *event; ivorbisfile->need_discont = FALSE; - /* if the pad is not usable, don't push it out */ - if (GST_PAD_IS_USABLE (ivorbisfile->srcpad)) { - /* get stream stats */ - samples = (gint64) (ov_pcm_tell (&ivorbisfile->vf)); + /* get stream stats */ + samples = (gint64) (ov_pcm_tell (&ivorbisfile->vf)); - discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, time, - GST_FORMAT_DEFAULT, samples, NULL); + event = + gst_event_new_newsegment (FALSE, 1.0, GST_FORMAT_TIME, time, + GST_CLOCK_TIME_NONE, 0); + + gst_pad_push_event (ivorbisfile->srcpad, event); - gst_pad_push (ivorbisfile->srcpad, GST_DATA (discont)); - } } + gst_buffer_set_caps (outbuf, GST_PAD_CAPS (ivorbisfile->srcpad)); + GST_BUFFER_SIZE (outbuf) = ret; - GST_BUFFER_TIMESTAMP (outbuf) = time; + /* FIX ME TO SET RIGHT TIMESTAMP + gint bufsize = ret / (ivorbisfile->width / 8); + GST_BUFFER_TIMESTAMP (outbuf) = time; + GST_BUFFER_DURATION (outbuf) = GST_SECOND * bufsize / (ivorbisfile->rate * ivorbisfile->channels); + */ + ivorbisfile->may_eos = TRUE; @@ -665,34 +709,10 @@ gst_ivorbisfile_loop (GstElement * element) ivorbisfile->total_bytes += GST_BUFFER_SIZE (outbuf); } - if (GST_PAD_IS_USABLE (ivorbisfile->srcpad)) - gst_pad_push (ivorbisfile->srcpad, GST_DATA (outbuf)); - else - gst_buffer_unref (outbuf); - } -} - -static const GstFormat * -gst_ivorbisfile_get_formats (GstPad * pad) -{ - static GstFormat src_formats[] = { - GST_FORMAT_TIME, - GST_FORMAT_BYTES, - GST_FORMAT_DEFAULT, - 0, - 0 - }; - static GstFormat sink_formats[] = { - GST_FORMAT_TIME, - GST_FORMAT_BYTES, - 0, - 0 - }; + gst_pad_push (ivorbisfile->srcpad, outbuf); - src_formats[3] = logical_stream_format; - sink_formats[2] = logical_stream_format; + } - return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats); } static gboolean @@ -706,7 +726,7 @@ gst_ivorbisfile_src_convert (GstPad * pad, Ivorbisfile *ivorbisfile; vorbis_info *vi; - ivorbisfile = GST_IVORBISFILE (gst_pad_get_parent (pad)); + ivorbisfile = GST_IVORBISFILE (GST_PAD_PARENT (pad)); vi = ov_info (&ivorbisfile->vf, -1); bytes_per_sample = vi->channels * 2; @@ -803,6 +823,32 @@ gst_ivorbisfile_src_convert (GstPad * pad, return res; } +static gboolean +gst_ivorbisfile_sink_query (GstPad * pad, GstQuery * query) +{ + gboolean res; + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_CONVERT: + { + GstFormat src_fmt, dest_fmt; + gint64 src_val, dest_val; + + /* peel off input */ + gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); + if ((res = gst_ivorbisfile_sink_convert (pad, src_fmt, src_val, + &dest_fmt, &dest_val))) { + gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val); + } + break; + } + default: + res = FALSE; + break; + } + return res; +} + static gboolean gst_ivorbisfile_sink_convert (GstPad * pad, GstFormat src_format, gint64 src_value, @@ -811,7 +857,7 @@ gst_ivorbisfile_sink_convert (GstPad * pad, gboolean res = TRUE; Ivorbisfile *ivorbisfile; - ivorbisfile = GST_IVORBISFILE (gst_pad_get_parent (pad)); + ivorbisfile = GST_IVORBISFILE (GST_PAD_PARENT (pad)); switch (src_format) { case GST_FORMAT_BYTES: @@ -851,11 +897,23 @@ gst_ivorbisfile_sink_convert (GstPad * pad, } static const GstQueryType * -gst_ivorbisfile_get_query_types (GstPad * pad) +gst_ivorbisfile_get_sink_query_types (GstPad * pad) +{ + static const GstQueryType types[] = { + GST_QUERY_CONVERT, + 0 + }; + + return types; +} + +static const GstQueryType * +gst_ivorbisfile_get_src_query_types (GstPad * pad) { static const GstQueryType types[] = { - GST_QUERY_TOTAL, GST_QUERY_POSITION, + GST_QUERY_DURATION, + GST_QUERY_CONVERT, 0 }; @@ -864,103 +922,194 @@ gst_ivorbisfile_get_query_types (GstPad * pad) /* handles queries for location in the stream in the requested format */ static gboolean -gst_ivorbisfile_src_query (GstPad * pad, GstQueryType type, - GstFormat * format, gint64 * value) +gst_ivorbisfile_src_query (GstPad * pad, GstQuery * query) { gboolean res = TRUE; Ivorbisfile *ivorbisfile; vorbis_info *vi; - ivorbisfile = GST_IVORBISFILE (gst_pad_get_parent (pad)); + ivorbisfile = GST_IVORBISFILE (GST_PAD_PARENT (pad)); vi = ov_info (&ivorbisfile->vf, -1); - switch (type) { - case GST_QUERY_TOTAL: + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_POSITION: { - switch (*format) { + + GstFormat format; + GstFormat rformat = GST_FORMAT_TIME; + gint64 cur; + GstPad *peer; + + /* save requested format */ + gst_query_parse_position (query, &format, NULL); + + /* query peer for current position in time */ + gst_query_set_position (query, GST_FORMAT_TIME, -1); + + if ((peer = gst_pad_get_peer (ivorbisfile->sinkpad)) == NULL) + goto error; + + if (!gst_pad_query_position (peer, &rformat, &cur)) { + GST_LOG_OBJECT (ivorbisfile, "query on peer pad failed"); + gst_object_unref (peer); + goto error; + } + gst_object_unref (peer); + + if (format != rformat) { + gst_ivorbisfile_src_convert (pad, rformat, cur, &format, &cur); + } + + switch (format) { case GST_FORMAT_DEFAULT: if (ivorbisfile->vf.seekable) - *value = ov_pcm_total (&ivorbisfile->vf, -1); + cur = ov_pcm_tell (&ivorbisfile->vf); else - return FALSE; + cur = ivorbisfile->total_bytes / (vi->channels * 2); break; - case GST_FORMAT_BYTES: + case GST_FORMAT_TIME: if (ivorbisfile->vf.seekable) - *value = ov_pcm_total (&ivorbisfile->vf, -1) * vi->channels * 2; + cur = (gint64) (ov_time_tell (&ivorbisfile->vf) * GST_SECOND); else - return FALSE; + cur = ivorbisfile->total_bytes * GST_SECOND + / (vi->rate * vi->channels * 2); break; - case GST_FORMAT_TIME: + case GST_FORMAT_BYTES: if (ivorbisfile->vf.seekable) - *value = - (gint64) (ov_time_total (&ivorbisfile->vf, -1) * GST_SECOND); + cur = ov_pcm_tell (&ivorbisfile->vf) * vi->channels * 2; else - return FALSE; + cur = ivorbisfile->total_bytes; break; default: - if (*format == logical_stream_format) { + if (format == logical_stream_format) { if (ivorbisfile->vf.seekable) - *value = ivorbisfile->vf.links; + cur = ivorbisfile->current_link; else return FALSE; } else res = FALSE; break; } + + gst_query_set_position (query, format, cur); + break; } - case GST_QUERY_POSITION: - switch (*format) { - case GST_FORMAT_TIME: + case GST_QUERY_DURATION: + { + + GstFormat format; + GstFormat rformat = GST_FORMAT_TIME; + gint64 cur; + GstPad *peer; + + /* save requested format */ + gst_query_parse_position (query, &format, NULL); + + /* query peer for current position in time */ + gst_query_set_position (query, GST_FORMAT_TIME, -1); + + if ((peer = gst_pad_get_peer (ivorbisfile->sinkpad)) == NULL) + goto error; + + if (!gst_pad_query_position (peer, &rformat, &cur)) { + GST_LOG_OBJECT (ivorbisfile, "query on peer pad failed"); + gst_object_unref (peer); + goto error; + } + gst_object_unref (peer); + + if (format != rformat) { + gst_ivorbisfile_src_convert (pad, rformat, cur, &format, &cur); + } + + switch (format) { + case GST_FORMAT_DEFAULT: if (ivorbisfile->vf.seekable) - *value = (gint64) (ov_time_tell (&ivorbisfile->vf) * GST_SECOND); + cur = ov_pcm_total (&ivorbisfile->vf, -1); else - *value = ivorbisfile->total_bytes * GST_SECOND - / (vi->rate * vi->channels * 2); + return FALSE; break; case GST_FORMAT_BYTES: if (ivorbisfile->vf.seekable) - *value = ov_pcm_tell (&ivorbisfile->vf) * vi->channels * 2; + cur = ov_pcm_total (&ivorbisfile->vf, -1) * vi->channels * 2; else - *value = ivorbisfile->total_bytes; + return FALSE; break; - case GST_FORMAT_DEFAULT: + case GST_FORMAT_TIME: if (ivorbisfile->vf.seekable) - *value = ov_pcm_tell (&ivorbisfile->vf); + cur = (gint64) (ov_time_total (&ivorbisfile->vf, -1) * GST_SECOND); else - *value = ivorbisfile->total_bytes / (vi->channels * 2); + return FALSE; break; default: - if (*format == logical_stream_format) { + if (format == logical_stream_format) { if (ivorbisfile->vf.seekable) - *value = ivorbisfile->current_link; + cur = ivorbisfile->vf.links; else return FALSE; } else res = FALSE; break; } + + gst_query_set_position (query, format, cur); + + break; + } + case GST_QUERY_CONVERT: + { + GstFormat src_fmt, dest_fmt; + gint64 src_val, dest_val; + + /* peel off input */ + gst_query_parse_convert (query, &src_fmt, &src_val, NULL, NULL); + if ((res = gst_ivorbisfile_src_convert (pad, src_fmt, src_val, + &dest_fmt, &dest_val))) { + gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val); + } break; + } default: res = FALSE; break; } return res; + +error: + + return FALSE; + } -static const GstEventMask * -gst_ivorbisfile_get_event_masks (GstPad * pad) + +static gboolean +gst_ivorbisfile_sink_event (GstPad * pad, GstEvent * event) { - static const GstEventMask masks[] = { - {GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_ACCURATE}, - {0,} - }; - return masks; + Ivorbisfile *ivorbisfile; + + ivorbisfile = GST_IVORBISFILE (GST_PAD_PARENT (pad)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_EOS: + GST_DEBUG ("eos"); + ov_clear (&ivorbisfile->vf); + ivorbisfile->eos = TRUE; + break; + case GST_EVENT_NEWSEGMENT: + GST_DEBUG ("discont"); + ivorbisfile->need_discont = TRUE; + default: + break; + } + + return gst_pad_event_default (pad, event); } + /* handle events on src pad */ static gboolean gst_ivorbisfile_src_event (GstPad * pad, GstEvent * event) @@ -976,6 +1125,7 @@ gst_ivorbisfile_src_event (GstPad * pad, GstEvent * event) gint64 offset; vorbis_info *vi; GstFormat format; + GstSeekFlags flags; GST_DEBUG ("ivorbisfile: handling seek event on pad %s:%s", GST_DEBUG_PAD_NAME (pad)); @@ -985,16 +1135,15 @@ gst_ivorbisfile_src_event (GstPad * pad, GstEvent * event) return FALSE; } - offset = GST_EVENT_SEEK_OFFSET (event); - format = GST_EVENT_SEEK_FORMAT (event); + gst_event_parse_seek (event, NULL, &format, &flags, NULL, &offset, NULL, + NULL); switch (format) { case GST_FORMAT_TIME: ivorbisfile->seek_pending = TRUE; ivorbisfile->seek_value = offset; ivorbisfile->seek_format = format; - ivorbisfile->seek_accurate = GST_EVENT_SEEK_FLAGS (event) - & GST_SEEK_FLAG_ACCURATE; + ivorbisfile->seek_accurate = flags & GST_SEEK_FLAG_ACCURATE; break; case GST_FORMAT_BYTES: vi = ov_info (&ivorbisfile->vf, -1); @@ -1009,16 +1158,14 @@ gst_ivorbisfile_src_event (GstPad * pad, GstEvent * event) ivorbisfile->seek_pending = TRUE; ivorbisfile->seek_value = offset; ivorbisfile->seek_format = format; - ivorbisfile->seek_accurate = GST_EVENT_SEEK_FLAGS (event) - & GST_SEEK_FLAG_ACCURATE; + ivorbisfile->seek_accurate = flags & GST_SEEK_FLAG_ACCURATE; break; default: if (format == logical_stream_format) { ivorbisfile->seek_pending = TRUE; ivorbisfile->seek_value = offset; ivorbisfile->seek_format = format; - ivorbisfile->seek_accurate = GST_EVENT_SEEK_FLAGS (event) - & GST_SEEK_FLAG_ACCURATE; + ivorbisfile->seek_accurate = flags & GST_SEEK_FLAG_ACCURATE; } else { GST_DEBUG ("unhandled seek format"); res = FALSE; @@ -1040,31 +1187,39 @@ done: static GstStateChangeReturn gst_ivorbisfile_change_state (GstElement * element, GstStateChange transition) { + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; Ivorbisfile *ivorbisfile = GST_IVORBISFILE (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: + /* fall through */ case GST_STATE_CHANGE_READY_TO_PAUSED: ivorbisfile->restart = TRUE; - ivorbisfile->bs = gst_bytestream_new (ivorbisfile->sinkpad); break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: ivorbisfile->eos = FALSE; + 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_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: ov_clear (&ivorbisfile->vf); - gst_bytestream_destroy (ivorbisfile->bs); break; case GST_STATE_CHANGE_READY_TO_NULL: default: break; } - if (GST_ELEMENT_CLASS (parent_class)->change_state) - return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - return GST_STATE_CHANGE_SUCCESS; + + return ret; } static void -- cgit v1.2.1