summaryrefslogtreecommitdiff
path: root/multimedia/gstreamer-plugins-ugly/files/patch-gst_mpegaudioparse_gstmpegaudioparse.c
diff options
context:
space:
mode:
Diffstat (limited to 'multimedia/gstreamer-plugins-ugly/files/patch-gst_mpegaudioparse_gstmpegaudioparse.c')
-rw-r--r--multimedia/gstreamer-plugins-ugly/files/patch-gst_mpegaudioparse_gstmpegaudioparse.c733
1 files changed, 0 insertions, 733 deletions
diff --git a/multimedia/gstreamer-plugins-ugly/files/patch-gst_mpegaudioparse_gstmpegaudioparse.c b/multimedia/gstreamer-plugins-ugly/files/patch-gst_mpegaudioparse_gstmpegaudioparse.c
deleted file mode 100644
index 6c1d5b594cd0..000000000000
--- a/multimedia/gstreamer-plugins-ugly/files/patch-gst_mpegaudioparse_gstmpegaudioparse.c
+++ /dev/null
@@ -1,733 +0,0 @@
---- gst/mpegaudioparse/gstmpegaudioparse.c.orig 2007-12-17 00:16:51.000000000 -0500
-+++ gst/mpegaudioparse/gstmpegaudioparse.c 2007-12-17 00:17:13.000000000 -0500
-@@ -29,6 +29,7 @@
- GST_DEBUG_CATEGORY_STATIC (mp3parse_debug);
- #define GST_CAT_DEFAULT mp3parse_debug
-
-+
- /* elementfactory information */
- static GstElementDetails mp3parse_details = {
- "MPEG1 Audio Parser",
-@@ -71,8 +72,9 @@ enum
-
-
- static void gst_mp3parse_class_init (GstMPEGAudioParseClass * klass);
--static void gst_mp3parse_base_init (GstMPEGAudioParseClass * klass);
--static void gst_mp3parse_init (GstMPEGAudioParse * mp3parse);
-+static void gst_mp3parse_base_init (gpointer klass);
-+static void gst_mp3parse_init (GstMPEGAudioParse * mp3parse,
-+ GstMPEGAudioParseClass * klass);
-
- static gboolean gst_mp3parse_sink_event (GstPad * pad, GstEvent * event);
- static GstFlowReturn gst_mp3parse_chain (GstPad * pad, GstBuffer * buffer);
-@@ -95,35 +97,11 @@ static gboolean mp3parse_bytepos_to_time
- static gboolean
- mp3parse_total_bytes (GstMPEGAudioParse * mp3parse, gint64 * total);
-
--static GstElementClass *parent_class = NULL;
--
- /*static guint gst_mp3parse_signals[LAST_SIGNAL] = { 0 }; */
-
--GType
--gst_mp3parse_get_type (void)
--{
-- static GType mp3parse_type = 0;
--
-- if (!mp3parse_type) {
-- static const GTypeInfo mp3parse_info = {
-- sizeof (GstMPEGAudioParseClass),
-- (GBaseInitFunc) gst_mp3parse_base_init,
-- NULL,
-- (GClassInitFunc) gst_mp3parse_class_init,
-- NULL,
-- NULL,
-- sizeof (GstMPEGAudioParse),
-- 0,
-- (GInstanceInitFunc) gst_mp3parse_init,
-- };
-+GST_BOILERPLATE (GstMPEGAudioParse, gst_mp3parse, GstElement, GST_TYPE_ELEMENT);
-
-- mp3parse_type = g_type_register_static (GST_TYPE_ELEMENT,
-- "GstMPEGAudioParse", &mp3parse_info, 0);
-- }
-- return mp3parse_type;
--}
--
--static guint mp3types_bitrates[2][3][16] = {
-+static const guint mp3types_bitrates[2][3][16] = {
- {
- {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448,},
- {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384,},
-@@ -136,7 +114,7 @@ static guint mp3types_bitrates[2][3][16]
- },
- };
-
--static guint mp3types_freqs[3][3] = { {44100, 48000, 32000},
-+static const guint mp3types_freqs[3][3] = { {44100, 48000, 32000},
- {22050, 24000, 16000},
- {11025, 12000, 8000}
- };
-@@ -218,13 +196,14 @@ mp3_caps_create (guint layer, guint chan
- new = gst_caps_new_simple ("audio/mpeg",
- "mpegversion", G_TYPE_INT, 1,
- "layer", G_TYPE_INT, layer,
-- "rate", G_TYPE_INT, samplerate, "channels", G_TYPE_INT, channels, NULL);
-+ "rate", G_TYPE_INT, samplerate,
-+ "channels", G_TYPE_INT, channels, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
-
- return new;
- }
-
- static void
--gst_mp3parse_base_init (GstMPEGAudioParseClass * klass)
-+gst_mp3parse_base_init (gpointer klass)
- {
- GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
-
-@@ -265,8 +244,8 @@ gst_mp3parse_reset (GstMPEGAudioParse *
- {
- mp3parse->skip = 0;
- mp3parse->resyncing = TRUE;
-- mp3parse->cur_offset = -1;
- mp3parse->next_ts = GST_CLOCK_TIME_NONE;
-+ mp3parse->cur_offset = -1;
-
- mp3parse->tracked_offset = 0;
- mp3parse->pending_ts = GST_CLOCK_TIME_NONE;
-@@ -276,6 +255,7 @@ gst_mp3parse_reset (GstMPEGAudioParse *
-
- mp3parse->rate = mp3parse->channels = mp3parse->layer = -1;
- mp3parse->version = 1;
-+ mp3parse->max_bitreservoir = GST_CLOCK_TIME_NONE;
-
- mp3parse->avg_bitrate = 0;
- mp3parse->bitrate_sum = 0;
-@@ -285,21 +265,42 @@ gst_mp3parse_reset (GstMPEGAudioParse *
-
- mp3parse->xing_flags = 0;
- mp3parse->xing_bitrate = 0;
-+
-+ if (mp3parse->seek_table) {
-+ g_list_foreach (mp3parse->seek_table, (GFunc) g_free, NULL);
-+ g_list_free (mp3parse->seek_table);
-+ mp3parse->seek_table = NULL;
-+ }
-+
-+ g_mutex_lock (mp3parse->pending_accurate_seeks_lock);
-+ if (mp3parse->pending_accurate_seeks) {
-+ g_slist_foreach (mp3parse->pending_accurate_seeks, (GFunc) g_free, NULL);
-+ g_slist_free (mp3parse->pending_accurate_seeks);
-+ mp3parse->pending_accurate_seeks = NULL;
-+ }
-+ g_mutex_unlock (mp3parse->pending_accurate_seeks_lock);
-+
-+ if (mp3parse->pending_segment) {
-+ GstEvent **eventp = &mp3parse->pending_segment;
-+
-+ gst_event_replace (eventp, NULL);
-+ }
-+
-+ mp3parse->exact_position = FALSE;
-+ gst_segment_init (&mp3parse->segment, GST_FORMAT_TIME);
- }
-
- static void
--gst_mp3parse_init (GstMPEGAudioParse * mp3parse)
-+gst_mp3parse_init (GstMPEGAudioParse * mp3parse, GstMPEGAudioParseClass * klass)
- {
- mp3parse->sinkpad =
-- gst_pad_new_from_template (gst_static_pad_template_get
-- (&mp3_sink_template), "sink");
-+ gst_pad_new_from_static_template (&mp3_sink_template, "sink");
- gst_pad_set_event_function (mp3parse->sinkpad, gst_mp3parse_sink_event);
- gst_pad_set_chain_function (mp3parse->sinkpad, gst_mp3parse_chain);
- gst_element_add_pad (GST_ELEMENT (mp3parse), mp3parse->sinkpad);
-
- mp3parse->srcpad =
-- gst_pad_new_from_template (gst_static_pad_template_get
-- (&mp3_src_template), "src");
-+ gst_pad_new_from_static_template (&mp3_src_template, "src");
- gst_pad_use_fixed_caps (mp3parse->srcpad);
- gst_pad_set_event_function (mp3parse->srcpad, mp3parse_src_event);
- gst_pad_set_query_function (mp3parse->srcpad, mp3parse_src_query);
-@@ -307,6 +308,7 @@ gst_mp3parse_init (GstMPEGAudioParse * m
- gst_element_add_pad (GST_ELEMENT (mp3parse), mp3parse->srcpad);
-
- mp3parse->adapter = gst_adapter_new ();
-+ mp3parse->pending_accurate_seeks_lock = g_mutex_new ();
-
- gst_mp3parse_reset (mp3parse);
- }
-@@ -316,10 +318,14 @@ gst_mp3parse_dispose (GObject * object)
- {
- GstMPEGAudioParse *mp3parse = GST_MP3PARSE (object);
-
-+ gst_mp3parse_reset (mp3parse);
-+
- if (mp3parse->adapter) {
- g_object_unref (mp3parse->adapter);
- mp3parse->adapter = NULL;
- }
-+ g_mutex_free (mp3parse->pending_accurate_seeks_lock);
-+ mp3parse->pending_accurate_seeks_lock = NULL;
-
- G_OBJECT_CLASS (parent_class)->dispose (object);
- }
-@@ -329,6 +335,7 @@ gst_mp3parse_sink_event (GstPad * pad, G
- {
- gboolean res;
- GstMPEGAudioParse *mp3parse;
-+ GstEvent **eventp;
-
- mp3parse = GST_MP3PARSE (gst_pad_get_parent (pad));
-
-@@ -343,6 +350,59 @@ gst_mp3parse_sink_event (GstPad * pad, G
- gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
- &format, &start, &stop, &pos);
-
-+ g_mutex_lock (mp3parse->pending_accurate_seeks_lock);
-+ if (format == GST_FORMAT_BYTES && mp3parse->pending_accurate_seeks) {
-+ MPEGAudioPendingAccurateSeek *seek = NULL;
-+ GSList *node;
-+
-+ for (node = mp3parse->pending_accurate_seeks; node; node = node->next) {
-+ MPEGAudioPendingAccurateSeek *tmp = node->data;
-+
-+ if (tmp->upstream_start == pos) {
-+ seek = tmp;
-+ break;
-+ }
-+ }
-+ if (seek) {
-+ GstSegment *s = &seek->segment;
-+
-+ event =
-+ gst_event_new_new_segment_full (FALSE, s->rate, s->applied_rate,
-+ GST_FORMAT_TIME, s->start, s->stop, s->last_stop);
-+
-+ mp3parse->segment = seek->segment;
-+
-+ mp3parse->resyncing = FALSE;
-+ mp3parse->cur_offset = pos;
-+ mp3parse->next_ts = seek->timestamp_start;
-+ mp3parse->pending_ts = GST_CLOCK_TIME_NONE;
-+ mp3parse->tracked_offset = 0;
-+
-+ gst_event_parse_new_segment_full (event, &update, &rate,
-+ &applied_rate, &format, &start, &stop, &pos);
-+
-+ GST_DEBUG_OBJECT (mp3parse,
-+ "Pushing accurate newseg rate %g, applied rate %g, "
-+ "format %d, start %lld, stop %lld, pos %lld\n", rate,
-+ applied_rate, format, start, stop, pos);
-+
-+ g_free (seek);
-+ mp3parse->pending_accurate_seeks =
-+ g_slist_delete_link (mp3parse->pending_accurate_seeks, node);
-+
-+ g_mutex_unlock (mp3parse->pending_accurate_seeks_lock);
-+ res = gst_pad_push_event (mp3parse->srcpad, event);
-+
-+ return res;
-+ } else {
-+ GST_WARNING_OBJECT (mp3parse,
-+ "Accurate seek not possible, didn't get an appropiate upstream segment");
-+ }
-+ }
-+ g_mutex_unlock (mp3parse->pending_accurate_seeks_lock);
-+
-+ mp3parse->exact_position = FALSE;
-+
- if (format == GST_FORMAT_BYTES) {
- GstClockTime seg_start, seg_stop, seg_pos;
-
-@@ -356,8 +416,9 @@ gst_mp3parse_sink_event (GstPad * pad, G
- GST_FORMAT_TIME, seg_start, seg_stop, seg_pos);
- format = GST_FORMAT_TIME;
- GST_DEBUG_OBJECT (mp3parse, "Converted incoming segment to TIME. "
-- "start = %" G_GINT64_FORMAT ", stop = %" G_GINT64_FORMAT
-- "pos = %" G_GINT64_FORMAT, seg_start, seg_stop, seg_pos);
-+ "start = %" GST_TIME_FORMAT ", stop = %" GST_TIME_FORMAT
-+ ", pos = %" GST_TIME_FORMAT, GST_TIME_ARGS (seg_start),
-+ GST_TIME_ARGS (seg_stop), GST_TIME_ARGS (seg_pos));
- }
- }
-
-@@ -368,6 +429,7 @@ gst_mp3parse_sink_event (GstPad * pad, G
- event = gst_event_new_new_segment_full (update, rate, applied_rate,
- GST_FORMAT_TIME, 0, GST_CLOCK_TIME_NONE, 0);
- }
-+
- mp3parse->resyncing = TRUE;
- mp3parse->cur_offset = -1;
- mp3parse->next_ts = GST_CLOCK_TIME_NONE;
-@@ -379,12 +441,23 @@ gst_mp3parse_sink_event (GstPad * pad, G
- GST_DEBUG_OBJECT (mp3parse, "Pushing newseg rate %g, applied rate %g, "
- "format %d, start %lld, stop %lld, pos %lld\n",
- rate, applied_rate, format, start, stop, pos);
-- res = gst_pad_push_event (mp3parse->srcpad, event);
-+
-+ gst_segment_set_newsegment_full (&mp3parse->segment, update, rate,
-+ applied_rate, format, start, stop, pos);
-+
-+ /* save the segment for later, right before we push a new buffer so that
-+ * the caps are fixed and the next linked element can receive the segment. */
-+ eventp = &mp3parse->pending_segment;
-+ gst_event_replace (eventp, event);
-+ gst_event_unref (event);
-+ res = TRUE;
- break;
- }
- case GST_EVENT_FLUSH_STOP:
- /* Clear our adapter and set up for a new position */
- gst_adapter_clear (mp3parse->adapter);
-+ eventp = &mp3parse->pending_segment;
-+ gst_event_replace (eventp, NULL);
- res = gst_pad_push_event (mp3parse->srcpad, event);
- break;
- default:
-@@ -397,14 +470,26 @@ gst_mp3parse_sink_event (GstPad * pad, G
- return res;
- }
-
-+static MPEGAudioSeekEntry *
-+mp3parse_seek_table_last_entry (GstMPEGAudioParse * mp3parse)
-+{
-+ MPEGAudioSeekEntry *ret = NULL;
-+
-+ if (mp3parse->seek_table) {
-+ ret = mp3parse->seek_table->data;
-+ }
-+
-+ return ret;
-+}
-+
- /* Prepare a buffer of the indicated size, timestamp it and output */
- static GstFlowReturn
- gst_mp3parse_emit_frame (GstMPEGAudioParse * mp3parse, guint size)
- {
- GstBuffer *outbuf;
- guint bitrate;
--
-- GST_DEBUG_OBJECT (mp3parse, "pushing buffer of %d bytes", size);
-+ GstFlowReturn ret = GST_FLOW_OK;
-+ GstClockTime push_start;
-
- outbuf = gst_adapter_take_buffer (mp3parse->adapter, size);
-
-@@ -456,6 +541,22 @@ gst_mp3parse_emit_frame (GstMPEGAudioPar
- }
- }
-
-+ if (GST_BUFFER_TIMESTAMP (outbuf) == 0)
-+ mp3parse->exact_position = TRUE;
-+
-+ if (mp3parse->exact_position && (!mp3parse->seek_table ||
-+ (mp3parse_seek_table_last_entry (mp3parse))->byte <
-+ GST_BUFFER_OFFSET (outbuf))) {
-+ MPEGAudioSeekEntry *entry = g_new0 (MPEGAudioSeekEntry, 1);
-+
-+ entry->byte = mp3parse->cur_offset;
-+ entry->timestamp = GST_BUFFER_TIMESTAMP (outbuf);
-+ mp3parse->seek_table = g_list_prepend (mp3parse->seek_table, entry);
-+ GST_DEBUG_OBJECT (mp3parse, "Adding index entry %" GST_TIME_FORMAT
-+ " @ offset 0x%08" G_GINT64_MODIFIER "x",
-+ GST_TIME_ARGS (entry->timestamp), entry->byte);
-+ }
-+
- /* Update our byte offset tracking */
- if (mp3parse->cur_offset != -1) {
- mp3parse->cur_offset += size;
-@@ -483,7 +584,53 @@ gst_mp3parse_emit_frame (GstMPEGAudioPar
- mp3parse->srcpad, taglist);
- }
-
-- return gst_pad_push (mp3parse->srcpad, outbuf);
-+ /* We start pushing 9 frames earlier (29 frames for MPEG2) than
-+ * segment start to be able to decode the first frame we want.
-+ * 9 (29) frames are the theoretical maximum of frames that contain
-+ * data for the current frame (bit reservoir).
-+ */
-+
-+ if (mp3parse->segment.start == 0) {
-+ push_start = 0;
-+ } else if (GST_CLOCK_TIME_IS_VALID (mp3parse->max_bitreservoir)) {
-+ if (mp3parse->segment.start > mp3parse->max_bitreservoir)
-+ push_start = mp3parse->segment.start - mp3parse->max_bitreservoir;
-+ else
-+ push_start = 0;
-+ } else {
-+ push_start = mp3parse->segment.start;
-+ }
-+
-+ if (G_UNLIKELY ((GST_CLOCK_TIME_IS_VALID (push_start) &&
-+ GST_BUFFER_TIMESTAMP (outbuf) + GST_BUFFER_DURATION (outbuf)
-+ < push_start)
-+ || (GST_CLOCK_TIME_IS_VALID (mp3parse->segment.stop)
-+ && GST_BUFFER_TIMESTAMP (outbuf) >= mp3parse->segment.stop))) {
-+ GST_DEBUG_OBJECT (mp3parse,
-+ "Buffer outside of configured segment range %" GST_TIME_FORMAT
-+ " to %" GST_TIME_FORMAT ", dropping, timestamp %"
-+ GST_TIME_FORMAT ", offset 0x%08" G_GINT64_MODIFIER "x",
-+ GST_TIME_ARGS (push_start), GST_TIME_ARGS (mp3parse->segment.stop),
-+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
-+ GST_BUFFER_OFFSET (outbuf));
-+ gst_buffer_unref (outbuf);
-+ ret = GST_FLOW_OK;
-+ } else {
-+ GST_DEBUG_OBJECT (mp3parse,
-+ "pushing buffer of %d bytes, timestamp %" GST_TIME_FORMAT
-+ ", offset 0x%08" G_GINT64_MODIFIER "x", size,
-+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
-+ GST_BUFFER_OFFSET (outbuf));
-+ mp3parse->segment.last_stop = GST_BUFFER_TIMESTAMP (outbuf);
-+ /* push any pending segment now */
-+ if (mp3parse->pending_segment) {
-+ gst_pad_push_event (mp3parse->srcpad, mp3parse->pending_segment);
-+ mp3parse->pending_segment = NULL;
-+ }
-+ ret = gst_pad_push (mp3parse->srcpad, outbuf);
-+ }
-+
-+ return ret;
- }
-
- #define XING_FRAMES_FLAG 0x0001
-@@ -610,14 +757,41 @@ gst_mp3parse_handle_first_frame (GstMPEG
- mp3parse->xing_bytes = 0;
-
- if (xing_flags & XING_TOC_FLAG) {
-- gint i;
-+ int i, percent = 0;
-+ guchar *table = mp3parse->xing_seek_table;
-+
-+ /* xing seek table: percent time -> 1/256 bytepos */
-+ memcpy (mp3parse->xing_seek_table, data, 100);
-
-- for (i = 0; i < 100; i++) {
-- mp3parse->xing_seek_table[i] = data[0];
-- data++;
-+ /* build inverse table: 1/256 bytepos -> 1/100 percent time */
-+ for (i = 0; i < 256; i++) {
-+ while (percent < 99 && table[percent + 1] <= i)
-+ percent++;
-+
-+ if (table[percent] == i) {
-+ mp3parse->xing_seek_table_inverse[i] = percent * 100;
-+ } else if (table[percent] < i && percent < 99) {
-+ gdouble fa, fb, fx;
-+ gint a = percent, b = percent + 1;
-+
-+ fa = table[a];
-+ fb = table[b];
-+ fx = (b - a) / (fb - fa) * (i - fa) + a;
-+ mp3parse->xing_seek_table_inverse[i] = (guint16) (fx * 100);
-+ } else if (percent == 98 && table[percent + 1] <= i) {
-+ gdouble fa, fb, fx;
-+ gint a = percent + 1, b = 100;
-+
-+ fa = table[a];
-+ fb = 256.0;
-+ fx = (b - a) / (fb - fa) * (i - fa) + a;
-+ mp3parse->xing_seek_table_inverse[i] = (guint16) (fx * 100);
-+ }
- }
-+ data += 100;
- } else {
- memset (mp3parse->xing_seek_table, 0, 100);
-+ memset (mp3parse->xing_seek_table_inverse, 0, 256);
- }
-
- if (xing_flags & XING_VBR_SCALE_FLAG) {
-@@ -777,6 +951,9 @@ gst_mp3parse_chain (GstPad * pad, GstBuf
- mp3parse->spf = 1152;
- }
-
-+ mp3parse->max_bitreservoir = gst_util_uint64_scale (GST_SECOND,
-+ ((version == 1) ? 10 : 30) * mp3parse->spf, mp3parse->rate);
-+
- /* Check the first frame for a Xing header to get our total length */
- if (mp3parse->frame_count == 0) {
- /* For the first frame in the file, look for a Xing frame after
-@@ -930,6 +1107,45 @@ gst_mp3parse_change_state (GstElement *
- return result;
- }
-
-+static gboolean
-+mp3parse_total_bytes (GstMPEGAudioParse * mp3parse, gint64 * total)
-+{
-+ GstFormat fmt = GST_FORMAT_BYTES;
-+
-+ if (gst_pad_query_peer_duration (mp3parse->sinkpad, &fmt, total))
-+ return TRUE;
-+
-+ if (mp3parse->xing_flags & XING_BYTES_FLAG) {
-+ *total = mp3parse->xing_bytes;
-+ return TRUE;
-+ }
-+
-+ return FALSE;
-+}
-+
-+static gboolean
-+mp3parse_total_time (GstMPEGAudioParse * mp3parse, GstClockTime * total)
-+{
-+ gint64 total_bytes;
-+
-+ *total = GST_CLOCK_TIME_NONE;
-+
-+ if (mp3parse->xing_flags & XING_FRAMES_FLAG) {
-+ *total = mp3parse->xing_total_time;
-+ return TRUE;
-+ }
-+
-+ /* Calculate time from the measured bitrate */
-+ if (!mp3parse_total_bytes (mp3parse, &total_bytes))
-+ return FALSE;
-+
-+ if (total_bytes != -1
-+ && !mp3parse_bytepos_to_time (mp3parse, total_bytes, total))
-+ return FALSE;
-+
-+ return TRUE;
-+}
-+
- /* Convert a timestamp to the file position required to start decoding that
- * timestamp. For now, this just uses the avg bitrate. Later, use an
- * incrementally accumulated seek table */
-@@ -937,12 +1153,38 @@ static gboolean
- mp3parse_time_to_bytepos (GstMPEGAudioParse * mp3parse, GstClockTime ts,
- gint64 * bytepos)
- {
-+ gint64 total_bytes;
-+ GstClockTime total_time;
-+
- /* -1 always maps to -1 */
- if (ts == -1) {
- *bytepos = -1;
- return TRUE;
- }
-
-+ /* If XING seek table exists use this for time->byte conversion */
-+ if ((mp3parse->xing_flags & XING_TOC_FLAG) &&
-+ mp3parse_total_bytes (mp3parse, &total_bytes) &&
-+ mp3parse_total_time (mp3parse, &total_time)) {
-+ gdouble fa, fb, fx;
-+ gdouble percent =
-+ CLAMP ((100.0 * gst_util_guint64_to_gdouble (ts)) /
-+ gst_util_guint64_to_gdouble (total_time), 0.0, 100.0);
-+ gint index = CLAMP (percent, 0, 99);
-+
-+ fa = mp3parse->xing_seek_table[index];
-+ if (index < 99)
-+ fb = mp3parse->xing_seek_table[index + 1];
-+ else
-+ fb = 256.0;
-+
-+ fx = fa + (fb - fa) * (percent - index);
-+
-+ *bytepos = (1.0 / 256.0) * fx * total_bytes;
-+
-+ return TRUE;
-+ }
-+
- if (mp3parse->avg_bitrate == 0)
- goto no_bitrate;
-
-@@ -958,6 +1200,9 @@ static gboolean
- mp3parse_bytepos_to_time (GstMPEGAudioParse * mp3parse,
- gint64 bytepos, GstClockTime * ts)
- {
-+ gint64 total_bytes;
-+ GstClockTime total_time;
-+
- if (bytepos == -1) {
- *ts = GST_CLOCK_TIME_NONE;
- return TRUE;
-@@ -968,61 +1213,33 @@ mp3parse_bytepos_to_time (GstMPEGAudioPa
- return TRUE;
- }
-
-- /* Cannot convert anything except 0 if we don't have a bitrate yet */
-- if (mp3parse->avg_bitrate == 0)
-- return FALSE;
--
-- *ts = (GstClockTime) gst_util_uint64_scale (GST_SECOND, bytepos * 8,
-- mp3parse->avg_bitrate);
-- return TRUE;
--}
--
--static gboolean
--mp3parse_total_bytes (GstMPEGAudioParse * mp3parse, gint64 * total)
--{
-- GstQuery *query;
-- GstPad *peer;
--
-- if ((peer = gst_pad_get_peer (mp3parse->sinkpad)) != NULL) {
-- query = gst_query_new_duration (GST_FORMAT_BYTES);
-- gst_query_set_duration (query, GST_FORMAT_BYTES, -1);
--
-- if (gst_pad_query (peer, query)) {
-- gst_object_unref (peer);
-- gst_query_parse_duration (query, NULL, total);
-- return TRUE;
-- }
-- gst_object_unref (peer);
-- }
--
-- if (mp3parse->xing_flags & XING_BYTES_FLAG) {
-- *total = mp3parse->xing_bytes;
-- return TRUE;
-- }
--
-- return FALSE;
--}
-+ /* If XING seek table exists use this for byte->time conversion */
-+ if ((mp3parse->xing_flags & XING_TOC_FLAG) &&
-+ mp3parse_total_bytes (mp3parse, &total_bytes) &&
-+ mp3parse_total_time (mp3parse, &total_time)) {
-+ gdouble fa, fb, fx;
-+ gdouble pos = CLAMP ((bytepos * 256.0) / total_bytes, 0.0, 256.0);
-+ gint index = CLAMP (pos, 0, 255);
-+
-+ fa = mp3parse->xing_seek_table_inverse[index];
-+ if (index < 255)
-+ fb = mp3parse->xing_seek_table_inverse[index + 1];
-+ else
-+ fb = 10000.0;
-
--static gboolean
--mp3parse_total_time (GstMPEGAudioParse * mp3parse, GstClockTime * total)
--{
-- gint64 total_bytes;
-+ fx = fa + (fb - fa) * (pos - index);
-
-- *total = GST_CLOCK_TIME_NONE;
-+ *ts = (1.0 / 10000.0) * fx * gst_util_guint64_to_gdouble (total_time);
-
-- if (mp3parse->xing_flags & XING_FRAMES_FLAG) {
-- *total = mp3parse->xing_total_time;
- return TRUE;
- }
-
-- /* Calculate time from the measured bitrate */
-- if (!mp3parse_total_bytes (mp3parse, &total_bytes))
-- return FALSE;
--
-- if (total_bytes != -1
-- && !mp3parse_bytepos_to_time (mp3parse, total_bytes, total))
-+ /* Cannot convert anything except 0 if we don't have a bitrate yet */
-+ if (mp3parse->avg_bitrate == 0)
- return FALSE;
-
-+ *ts = (GstClockTime) gst_util_uint64_scale (GST_SECOND, bytepos * 8,
-+ mp3parse->avg_bitrate);
- return TRUE;
- }
-
-@@ -1036,11 +1253,12 @@ mp3parse_handle_seek (GstMPEGAudioParse
- gint64 cur, stop;
- gint64 byte_cur, byte_stop;
-
-- /* FIXME: Use GstSegment for tracking our position */
--
- gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
- &stop_type, &stop);
-
-+ GST_DEBUG_OBJECT (mp3parse, "Performing seek to %" GST_TIME_FORMAT,
-+ GST_TIME_ARGS (cur));
-+
- /* For any format other than TIME, see if upstream handles
- * it directly or fail. For TIME, try upstream, but do it ourselves if
- * it fails upstream */
-@@ -1055,6 +1273,90 @@ mp3parse_handle_seek (GstMPEGAudioParse
-
- /* Handle TIME based seeks by converting to a BYTE position */
-
-+ /* For accurate seeking get the frame 9 (MPEG1) or 29 (MPEG2) frames
-+ * before the one we want to seek to and push them all to the decoder.
-+ *
-+ * This is necessary because of the bit reservoir. See
-+ * http://www.mars.org/mailman/public/mad-dev/2002-May/000634.html
-+ *
-+ */
-+
-+ if (flags & GST_SEEK_FLAG_ACCURATE) {
-+ MPEGAudioPendingAccurateSeek *seek =
-+ g_new0 (MPEGAudioPendingAccurateSeek, 1);
-+ GstClockTime start;
-+
-+ seek->segment = mp3parse->segment;
-+
-+ gst_segment_set_seek (&seek->segment, rate, GST_FORMAT_TIME,
-+ flags, cur_type, cur, stop_type, stop, NULL);
-+
-+ if (!mp3parse->seek_table) {
-+ byte_cur = 0;
-+ byte_stop = -1;
-+ start = 0;
-+ } else {
-+ MPEGAudioSeekEntry *entry = NULL, *start_entry = NULL, *stop_entry = NULL;
-+ GList *start_node, *stop_node;
-+
-+ for (start_node = mp3parse->seek_table; start_node;
-+ start_node = start_node->next) {
-+ entry = start_node->data;
-+
-+ if (cur - mp3parse->max_bitreservoir >= entry->timestamp) {
-+ start_entry = entry;
-+ break;
-+ }
-+ }
-+
-+ if (!start_entry) {
-+ start_entry = mp3parse->seek_table->data;
-+ start = start_entry->timestamp;
-+ byte_cur = start_entry->byte;
-+ } else {
-+ start = start_entry->timestamp;
-+ byte_cur = start_entry->byte;
-+ }
-+
-+ for (stop_node = mp3parse->seek_table; stop_node;
-+ stop_node = stop_node->next) {
-+ entry = stop_node->data;
-+
-+ if (stop >= entry->timestamp) {
-+ stop_node = stop_node->prev;
-+ stop_entry = (stop_node) ? stop_node->data : NULL;
-+ break;
-+ }
-+ }
-+
-+ if (!stop_entry) {
-+ byte_stop = -1;
-+ } else {
-+ byte_stop = stop_entry->byte;
-+ }
-+
-+ }
-+ g_mutex_lock (mp3parse->pending_accurate_seeks_lock);
-+ event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
-+ byte_cur, stop_type, byte_stop);
-+ if (gst_pad_push_event (mp3parse->sinkpad, event)) {
-+ mp3parse->exact_position = TRUE;
-+ seek->upstream_start = byte_cur;
-+ seek->timestamp_start = start;
-+ mp3parse->pending_accurate_seeks =
-+ g_slist_prepend (mp3parse->pending_accurate_seeks, seek);
-+ g_mutex_unlock (mp3parse->pending_accurate_seeks_lock);
-+ return TRUE;
-+ } else {
-+ g_mutex_unlock (mp3parse->pending_accurate_seeks_lock);
-+ mp3parse->exact_position = TRUE;
-+ g_free (seek);
-+ return TRUE;
-+ }
-+ }
-+
-+ mp3parse->exact_position = FALSE;
-+
- /* Convert the TIME to the appropriate BYTE position at which to resume
- * decoding. */
- if (!mp3parse_time_to_bytepos (mp3parse, (GstClockTime) cur, &byte_cur))