From a44258dbe888e65da3151132978dc60825173759 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Thu, 12 Mar 2015 16:01:48 +0000 Subject: [PATCH] oggdemux: fix wrong duration on partial streams with a skeleton index When a stream has a skeleton index, the stream time is taken from that index. However, when part of the stream is captured, the index is invalid as its offsets are now wrong. To avoid this, we ignore the index when the last offset points beyond the end of the stream (when its byte length is known). https://bugzilla.gnome.org/show_bug.cgi?id=744070 --- ext/ogg/gstoggdemux.c | 76 +++++++++++++++++++++++++++++++++++++++---- ext/ogg/gstoggdemux.h | 2 ++ 2 files changed, 71 insertions(+), 7 deletions(-) diff --git a/ext/ogg/gstoggdemux.c b/ext/ogg/gstoggdemux.c index 77fd7deb75..c027b43788 100644 --- a/ext/ogg/gstoggdemux.c +++ b/ext/ogg/gstoggdemux.c @@ -586,6 +586,74 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet, GST_DEBUG_OBJECT (ogg, "packet duration %" G_GUINT64_FORMAT, duration); } + + /* If we get a hole at start, it might be we're catching a stream + * partway through. In that case, if the stream has an index, the + * index might be mooted. However, as it's totally valid to index + * a stream with a hole at start (ie, capturing a live stream and + * then index it), we now check whether the index references some + * offset beyond the byte length (if known). If this is the case, + * we can be reasonably sure we're getting a stream partway, with + * its index being now useless since we don't know how many bytes + * were skipped, preventing us from patching the index offsets to + * match the hole size. */ + if (!is_header && ogg->check_index_overflow) { + GstQuery *query; + GstFormat format; + int i; + gint64 length; + gboolean beyond; + + if (ogg->current_chain) { + query = gst_query_new_duration (GST_FORMAT_BYTES); + if (gst_pad_peer_query (ogg->sinkpad, query)) { + gst_query_parse_duration (query, &format, &length); + if (format == GST_FORMAT_BYTES && length >= 0) { + for (i = 0; i < ogg->current_chain->streams->len; i++) { + GstOggPad *ipad = + g_array_index (ogg->current_chain->streams, GstOggPad *, i); + if (!ipad->map.index) + continue; + beyond = ipad->map.n_index + && ipad->map.index[ipad->map.n_index - 1].offset >= length; + if (beyond) { + GST_WARNING_OBJECT (pad, "Index offsets beyong byte length"); + if (ipad->discont) { + /* hole - the index is most likely screwed up */ + GST_WARNING_OBJECT (ogg, "Discarding entire index"); + g_free (ipad->map.index); + ipad->map.index = NULL; + ipad->map.n_index = 0; + } else { + /* no hole - we can just clip the index if needed */ + GST_WARNING_OBJECT (ogg, "Clipping index"); + while (ipad->map.n_index > 0 + && ipad->map.index[ipad->map.n_index - 1].offset >= length) + ipad->map.n_index--; + if (ipad->map.n_index == 0) { + GST_WARNING_OBJECT (ogg, "The entire index was clipped"); + g_free (ipad->map.index); + ipad->map.index = NULL; + } + } + /* We can't trust the total time if the index goes beyond */ + ipad->map.total_time = -1; + } else { + /* use total time to update the total ogg time */ + if (ogg->total_time == -1) { + ogg->total_time = ipad->map.total_time; + } else if (ipad->map.total_time > 0) { + ogg->total_time = MAX (ogg->total_time, ipad->map.total_time); + } + } + } + } + } + gst_query_unref (query); + } + ogg->check_index_overflow = FALSE; + } + if (packet->b_o_s) { out_timestamp = GST_CLOCK_TIME_NONE; out_duration = GST_CLOCK_TIME_NONE; @@ -919,13 +987,7 @@ gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet) case GST_OGG_SKELETON_INDEX: gst_ogg_map_add_index (&skel_pad->map, &pad->map, packet->packet, packet->bytes); - - /* use total time to update the total ogg time */ - if (ogg->total_time == -1) { - ogg->total_time = skel_pad->map.total_time; - } else if (skel_pad->map.total_time > 0) { - ogg->total_time = MAX (ogg->total_time, skel_pad->map.total_time); - } + ogg->check_index_overflow = TRUE; break; default: break; diff --git a/ext/ogg/gstoggdemux.h b/ext/ogg/gstoggdemux.h index 742392f143..db1f393af3 100644 --- a/ext/ogg/gstoggdemux.h +++ b/ext/ogg/gstoggdemux.h @@ -148,6 +148,8 @@ struct _GstOggDemux useful for skewing when seeking */ guint64 max_packet_size, max_page_size; + gboolean check_index_overflow; + /* state */ GMutex chain_lock; /* we need the lock to protect the chains */ GArray *chains; /* list of chains we know */