summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorThiago Santos <ts.santos@sisa.samsung.com>2014-04-28 13:02:11 -0300
committerThiago Santos <ts.santos@sisa.samsung.com>2014-04-28 17:08:57 -0300
commit0a3bc6be1fc09a8aabde43505f9c3f0dfaf2ed94 (patch)
tree0d728f60fdbcb788983df29c9812efa8ad8f13fe /plugins
parent3b617f1fb22fd5d6bc14e79a2925ad149d2e350c (diff)
downloadgstreamer-0a3bc6be1fc09a8aabde43505f9c3f0dfaf2ed94.tar.gz
multiqueue: avoid signaling overrun on the first segment
When the first segment has position != 0 and position > max-size-time it will immediatelly cause the multiqueue to signal overrun. This can happen easily with adaptive streams when switching bitrates and starting a new group. The segment for this new group will have a position that is much greater than 0 and will lead to this issue. This is particularly harmful when the adaptive stream uses mpegts that doesn't emit no-more-pads and it might happen that only one of the stream pads was added when the multiqueue overruns and gets the group ready for exposing. So the user will only get audio or video. The solution is to fallback to the sink segment while the source pad has no segment. https://bugzilla.gnome.org/show_bug.cgi?id=729124
Diffstat (limited to 'plugins')
-rw-r--r--plugins/elements/gstmultiqueue.c30
1 files changed, 27 insertions, 3 deletions
diff --git a/plugins/elements/gstmultiqueue.c b/plugins/elements/gstmultiqueue.c
index cf2f6b985f..51b4390b9f 100644
--- a/plugins/elements/gstmultiqueue.c
+++ b/plugins/elements/gstmultiqueue.c
@@ -144,6 +144,9 @@ struct _GstSingleQueue
/* segments */
GstSegment sink_segment;
GstSegment src_segment;
+ gboolean has_src_segment; /* preferred over initializing the src_segment to
+ * UNDEFINED as this doesn't requires adding ifs
+ * in every segment usage */
/* position of src/sink */
GstClockTime sinktime, srctime;
@@ -826,6 +829,7 @@ gst_single_queue_flush (GstMultiQueue * mq, GstSingleQueue * sq, gboolean flush,
gst_single_queue_flush_queue (sq, full);
gst_segment_init (&sq->sink_segment, GST_FORMAT_TIME);
gst_segment_init (&sq->src_segment, GST_FORMAT_TIME);
+ sq->has_src_segment = FALSE;
/* All pads start off not-linked for a smooth kick-off */
sq->srcresult = GST_FLOW_OK;
sq->pushed = FALSE;
@@ -945,9 +949,27 @@ update_time_level (GstMultiQueue * mq, GstSingleQueue * sq)
sink_time = sq->sinktime;
if (sq->src_tainted) {
+ GstSegment *segment;
+ gint64 position;
+
+ if (sq->has_src_segment) {
+ segment = &sq->src_segment;
+ position = sq->src_segment.position;
+ } else {
+ /*
+ * If the src pad had no segment yet, use the sink segment
+ * to avoid signalling overrun if the received sink segment has a
+ * a position > max-size-time while the src pad time would be the default=0
+ *
+ * This can happen when switching pads on chained/adaptive streams and the
+ * new chain has a segment with a much larger position
+ */
+ segment = &sq->sink_segment;
+ position = sq->sink_segment.position;
+ }
+
src_time = sq->srctime =
- gst_segment_to_running_time (&sq->src_segment, GST_FORMAT_TIME,
- sq->src_segment.position);
+ gst_segment_to_running_time (segment, GST_FORMAT_TIME, position);
/* if we have a time, we become untainted and use the time */
if (G_UNLIKELY (src_time != GST_CLOCK_TIME_NONE))
sq->src_tainted = FALSE;
@@ -993,8 +1015,10 @@ apply_segment (GstMultiQueue * mq, GstSingleQueue * sq, GstEvent * event,
if (segment == &sq->sink_segment)
sq->sink_tainted = TRUE;
- else
+ else {
+ sq->has_src_segment = TRUE;
sq->src_tainted = TRUE;
+ }
GST_DEBUG_OBJECT (mq,
"queue %d, configured SEGMENT %" GST_SEGMENT_FORMAT, sq->id, segment);